일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 완전탐색
- dfs
- exec
- 프로세스
- paging
- 백트래킹
- Brute Force
- ascii_easy
- 가상메모리
- 시뮬레이션
- higunnew
- BOJ
- BFS
- 운영체제
- 삼성리서치
- 스케줄링
- 삼성기출
- 김건우
- 동기화문제
- Memory Management
- 알고리즘
- Deadlock
- 구현
- 컴공복전
- segmentation
- 데드락
- samsung research
- pwnable.kr
- 백준
- fork
- Today
- Total
gunnew의 잡설
pwnable.kr 4. flag (UPX unpacking problem) 본문
이번 문제는 뭘까... 두려움이 앞선다.
Reverse engineering 인듯 하다. 어떻게 하는 건지는 잘 모르겠지만 우선 다음 명령어를 통해 파일을 다운받자.
wget http://pwnable.kr/bin/flag
그리고 flag를 실행해보았더니 malloc을 했고, 거기에 flag를 strcpy 해 놓았단다. 그러면 이것도 뭐 gdb 겠거니 하면서 gdb를 켜보자.
1. gdb로 열어보기 |
띠용?? file을 열 수 없다고? 왜지? 흠... 그러면 한번 binary file을 열어보자.
2. UPX 다운로드 및 Unpacking |
자 이제 기계어로 된 binary file인 flag를 vi로 읽어보자. 그랬더니 위의 괴상한 문자들이 나오는데 그 와중에 UPX라는 글자가 보인다. UPX를 찾아보았더니 UPX는 아무튼 알집하고 비슷한 압축 툴인것 같다. 그럼 UPX를 다운받자.
근데 왜인지는 모르겠으나 다음과 같은 명령어를 통해 upx를 깔고 실행해 봤는데 안된다.
kimk@ubuntu:~/Desktop/security/flag$ sudo snap install upx
[sudo] password for kimk:
upx v0.2.3 from HanYec (hyc320) installed
kimk@ubuntu:~/Desktop/security/flag$ upx -d ./flag
Incorrect Usage.
그래서 한참을 찾다가 그냥 firefox로 들어가서 다운받아서 실행파일만 flag가 있는 폴더로 옮겨 버렸다. 이 사이트로 들어가서 최근 것 다운 받아서 압축풀고 밑에 사진대로 따라가면 된다.
https://github.com/upx/upx/releases
3. Unpacking 및 gdb 실행, disassembly code 분석 |
자! 이제 upx 실행파일도 가져왔겠다. unpacking을 해보자.
./upx -d flag를 하면 압축이 풀린다.
이제 gdb를 통해 disassembly code를 까보자.
위 코드를 가만히 보자니 일단 malloc을 통해 0x64 (100)bytes만큼 할당한 것까지는 눈에 띈다. 그 다음을 보면 0x0000000000401184 <+32>: mov rdx, QWORD PTR [rip+0x2c0ee5] 이 부분을 볼 수 있는데 rip는 64bit에서 다음 실행할 부분의 주소를 나타낸다. 그런데 rdx에다가 우리가 보고자 하는 <flag>가 있는 곳에 있는 값을 넘겨주었다. 아마 이 부분에는 문자열이 시작되므로 문자열의 주소가 저장되어 있을 것이다.
그리고
0x000000000040118b <+39>: mov rax, QWORD PTR [rbp-0x8]
이 부분을 통해서 rbp-0x8 즉, main 함수 내 스택에 있는 지역 변수에 있는 주소를 rax로 옮기고 이것을
0x0000000000401192 <+46>: mov rdi,rax
를 통해 rdi로 옮긴다.
또한
0x000000000040118f <+43>: mov rsi,rdx
이 부분을 통해서 그 문자열의 주소를 rsi로 옮겨 놓은 후에
0x0000000000401195 <+49>: call 0x400320
로 시스템 콜을 하는 것으로 보인다.
Dump of assembler code for function main:
0x0000000000401164 <+0>: push rbp
0x0000000000401165 <+1>: mov rbp,rsp
0x0000000000401168 <+4>: sub rsp,0x10
0x000000000040116c <+8>: mov edi,0x496658
0x0000000000401171 <+13>: call 0x402080
0x0000000000401176 <+18>: mov edi,0x64
0x000000000040117b <+23>: call 0x4099d0
0x0000000000401180 <+28>: mov QWORD PTR [rbp-0x8],rax
0x0000000000401184 <+32>: mov rdx, QWORD PTR [rip+0x2c0ee5] # 0x6c2070 <flag>
0x000000000040118b <+39>: mov rax, QWORD PTR [rbp-0x8]
0x000000000040118f <+43>: mov rsi,rdx
0x0000000000401192 <+46>: mov rdi,rax
0x0000000000401195 <+49>: call 0x400320
0x000000000040119a <+54>: mov eax,0x0
0x000000000040119f <+59>: leave
0x00000000004011a0 <+60>: ret
End of assembler dump.
(gdb) b *0x401195
Breakpoint 1 at 0x401195
(gdb) run
Starting program: /home/kimk/Desktop/security/flag/flag
I will malloc() and strcpy the flag there. take it.
Breakpoint 1, 0x0000000000401195 in main ()
이제 중단점에서 info reg를 통해 reg에 있는 값들을 살펴보자. 우리가 유심히 봐야하는 레지스터는 최종적으로 rsi와 rdi와 옮긴 것을 디스어셈블리 코드에서 확인했으니까 rsi와 rdi만 보면 된다. 사실 가만 생각해보면 rsi는 source index를, rdi는 destination index를 나타내는 레지스터이기 때문에 시스템 콜을 하기 전에 해당 레지스터에는 목표로 하는 작업을 위해 정확한 값이 들어가야 한다. 그러니까 시스템 콜을 하면 당연히 rsi에는 source가, rdi는 destination이 있을 거라 생각하기 때문에 우리는 source가 되는 부분에 있는 문자열을 보거나, 혹은 시스템 콜이 완료되고 rdi에 있는 문자열을 보면 된다.
먼저 rdi에 문자열로 뭐가 있는지 보기 위해
(gdb) x/s 0x6c96b0
을 입력했으나 밑에 사진과 같이 ""이 나온다. 아직 안 옮겨졌으니까 당연하다.
그럼 이제 next 실행하고 rdi를 다시 확인해보자.
짜잔! 정답이 나왔다. UPX...? ~~~ 이것이 우리가 목표로 하는 flag이다.
아 물론 rsi에 있는 값을 진작에 확인했어도 됐다. rsi에 0x496628이 있었으니까 거기에 있는 것을 문자열로 표현해봤더니 rdi랑 똑같다. (당연하지 strcpy인데)
'System Security' 카테고리의 다른 글
pwnable.kr 6. random (0) | 2020.02.05 |
---|---|
pwnable.kr 5. passcode (0) | 2020.02.04 |
pwnable.kr 3. bof (Buffer overflow) (Stack smashing) (0) | 2020.02.02 |
pwnable.kr 2. collision (0) | 2020.02.02 |
pwnable.kr 1. fd(File Descriptor) (0) | 2020.02.02 |