SKCTF_2019

![](https://liul14nimg.oss-cn-qingdao.aliyuncs.com/liul14nimg/Christmas Wallpaper.jpg)


*前段时间参加了SKCTF2019,并且最近推完了《三色绘恋》, 作为纪念, 这篇博文的所有配图都用《三色绘恋》里面的CG了~ 可爱的墨小菊作封面镇博~ *

这篇博文会持续更新,直到我把我会做的所有题都更一篇WP为止

AWD部分

  • 我没什么AWD经验, 登入服务器什么的还是现学的, 下载下来pwn以后也只是粗略分析… 忽视了一个大漏洞,导致pwn一直被打而没有进攻…

  • 我与进攻只差一个666。

  • 首先pwn的login是一个点, 这个通过被攻击流量直接拿到了打法。

用户名直接a上200个, 密码a上72个。

  • 但是这个流量里面含有太多攻击者的测试阶段, 这对第一次进行AWD流量分析的我产生了干扰。。。 再加上我不太会pwn,我以为要执行完所有攻击者的行为才能cat flag。

  • 但是运行过程中一直在调试… 忽略了最简单的666,起初还纳闷这个666是干什么的,直到赛后表哥讲解的时候才恍然大悟… 这心情感觉就像高考试卷没写名字一样…。

先暂时记录到这, 因为还没开始正式学pwn, 先从逆向学起~

MISC部分

0x01 unzip

  • 考察时间戳, 可以直接爆破压缩包密码。

时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数。

  • 可以直接从1550000000 开始爆破密码, 这样省时间。

  • 解开zip 得到flag。

0x02 二维码

  • 考察PIL库的运用, 编码与加解密。

  • 题目是给了一堆RGB值, 把它保存在一个文件里。 脚本附上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from PIL import Image

x = 280
y = 280

im = Image.new("RGB", (x, y))
file = open("D:\\RGB.txt",'r')

for i in range(0, x):
for j in range(0, y):
line = file.readline().replace('(','').replace(')','')
rgb = line.split(",")
im.putpixel((i, j), (int(rgb[0]), int(rgb[1]), int(rgb[2])))

im.show()
  • 得到二维码

  • 扫码得到:

ONYXE6LSIVXF6ZTUOZTXWRRRIRPWCZLWORIGCLJQG56Q====

  • base32解码得到:

sqryrEn_ftvg{F1D_aevtPa-07}

  • 9栏栅栏解密得到:

synt{DeP0qr_vF_va7rEfg1at-}

  • 凯撒解密得到:

flag{QrC0de_iS_in7eRst1ng-}

0x03 猜数

  • 考察写脚本能力或者说…耐心…

  • 这道题我是试了手撕了一百多次,得到了150个数据,然后得到了flag.

  • 这150个数据就不列出来了.

  • 这里学习大佬的利用pwntools的解法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from pwn import *
import time

t = ['679']#这个表示初始数据, 根据题目来的,因为第一个数需要输入679才对。

for x in range(0xff):#这里是设置需要循环的次数, 可根据需要调整, 这道题目150就够了。
p = remote('10.1.0.18',10000)
for c in t:
p.sendline(str(c))
p.sendline('a')#发送一个注定不合法的字符, 然后接收程序返回的正确数据。
time.sleep(0.1)#间隔0.1秒来防止由于网络问题出现的错误
t.append(p.recv().split('Good!\n')[-1].replace('\n',''))#接收并添加数据进入列表t
p.close()
#print t #这一步可以不要。
  • 这样的话, 如果数据和题目提供的数据完全相同的话, flag也就会跟着输出出来了。

0x04 Manchester

  • 考察图片隐写与曼彻斯特编码。

  • 在kali里面binwalk题目图片,发现里面还隐藏着一张图片, foremost分离出来以后是一堆类似于-. 这种。

  • 还没做完,等平台重新开放再更。

Crypto部分

0x01 签到题

  • 考察手速和仔细程度
  • 公告真该仔细看看。

0x02 RSA

  • 考察对RSA算法的理解与应用。

  • 之前见过的题目大都是已知pqe或ne推出d之类的,而这个题目是已知ned去反推pq。

  • 尝试对模n进行在线分解,但是无果, n实在太大了。

  • 又尝试进行正向爆破,看看谁(p)乘谁(q)等于模n,但是…n实在太大了, 数据都超出范围了…

  • 无奈只能上网找算法。

  • 脚本附上:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# -*- coding: UTF-8 -*-
import random

def gcd(a, b):
if a < b:
a, b = b, a
while b != 0:
temp = a % b
a = b
b = temp
return a

def getpq(n,e,d):
p = 1
q = 1
while p==1 and q==1:
k = d * e - 1
g = random.randint ( 0 , n )
while p==1 and q==1 and k % 2 == 0:
k /= 2
y = pow(g,k,n)
if y!=1 and gcd(y-1,n)>1:
p = gcd(y-1,n)
q = n/p
return p,q

def main():

n =16352578963372306131642407541567045533766691177138375676491913897592458965544068296813122740126583082006556217616296009516413202833698268845634497478988128850373221853516973259086845725813424850548682503827191121548693288763243619033224322698075987667531863213468223654181658012754897588147027437229269098246969811226129883327598021859724836993626315476699384610680857047403431430525708390695622848315322636785398223207468754197643541958599210127261345770914514670199047435085714403641469016212958361993969304545214061560160267760786482163373784437641808292654489343487613446165542988382687729593384887516272690654309
e =65537
d =9459928379973667430138068528059438139092368625339079253289560577985304435062213121398231875832264894458314629575455553485752685643743266654630829957442008775259776311585654014858165341757547284112061885158006881475740553532826576260839430343960738520822367975528644329172668877696208741007648370045520535298040161675407779239300466681615493892692265542290255408673533853011662134953869432632554008235340864803377610352438146264524770710345273439724107080190182918285547426166561803716644089414078389475072103315432638197578186106576626728869020366214077455194554930725576023274922741115941214789600089166754476449453

p,q = getpq(n,e,d)
print p
print q

if __name__ == '__main__':
main()
  • 由此可以得到pq,然后代入题目给的脚本。
1
2
3
4
5
6
7
8
9
10
11
12
13
from gmpy2 import invert
from md5 import md5
p = 121681461613856685891389697655082707982324934394003375745821514797619569583750841725694490585739982440237839675155146102668334623474524757328414864963814738071946391260695792366762521733527504377788503669628114869921159658618293030663730923781347146576731525405173348568491361155907470541865888995846800200299

q =134388416661738455437155072073325006890713121761597606147089758733385481112565493304597414841403553334452751594251761452974840757858360219741735123120957682353146947112071576479841838875008748813717254467137424822946053401492632307085887983816096569782409349352398269269865393361999329194582827715646840442991
e = 65537
n = p*q
phi = (p-1)*(q-1)
d = invert(e, phi)

print n, e, d

print "Flag: SKCTF{%s}" %md5(str(p + q)).hexdigest()
  • 运行得到flag:

SKCTF{e7ddad281ff7dfc99eb3379e0efd46f8}

0x03 xor

  • 题目是这么一堆字符…
1
rJeekZuQkZjfqpGWiZqNjJaLht+Qmd+snJaakZya356Rm9+rmpyXkZCTkJiG9b6bm42ajIzFysjG366WnpGInpGYnpGY362QnpvT37eKnpGYm56Q37uWjIuNlpyL09+ulpGYm56Q09+sl56Rm5CRmN+vjZCJlpGcmtPfzcnJysbP09+v0a3RvJeWkZ71rLS8q7mEzpvJnsnLm8rGzc/Nyp7LzcbNmp2Zy5mZxpyZxsvOzsuC
  • 比赛的时候对着这么一串字符与0~256都异或了一遍, 然并卵。

  • 殊不知需要先对这一串字符进行base64解密。。。。

  • 脚本附上:

1
2
3
4
5
6
7
8
9
# -*- coding: UTF-8 -*-
import base64
s = 'rJeekZuQkZjfqpGWiZqNjJaLht+Qmd+snJaakZya356Rm9+rmpyXkZCTkJiG9b6bm42ajIzFysjG366WnpGInpGYnpGY362QnpvT37eKnpGYm56Q37uWjIuNlpyL09+ulpGYm56Q09+sl56Rm5CRmN+vjZCJlpGcmtPfzcnJysbP09+v0a3RvJeWkZ71rLS8q7mEzpvJnsnLm8rGzc/Nyp7LzcbNmp2Zy5mZxpyZxsvOzsuC'
str = base64.b64decode(s)
for i in range(0xff+1):
ss = ''
for x in str:
ss+=chr(ord(x)^i)
print ss

  • 运行结果挺有意思的…
  • flag:

SKCTF{1d6a64d592025a4292ebf4ff9cf94114}

0x04 抓捕贪污犯

  • 考察仿射密码

  • 题目没记下来…等平台再开的时候再更…

  • 基本思路就是先通过题目的提示 写个小算法得到a与b, 然后对题目中那一串字符串进行仿射解密。

Reverse 部分

0x01 CUBE

  • 考察angr的运用。

  • 之前曾经接触过一些angr方面的题目, 但是与之前题目不同的是,这道题的avoid的地方有多个,谷歌到需要使用元组来进行avoid。

  • 但是比赛的时候并没有完整地解出来这道题目。因为考虑的方向有所偏差,陷入一片迷茫。

  • 比赛时我的find地址选的0x401015,这样导致无法执行到下面0x4010C1的printf后门。 哭,再一次辜负了表哥的期望… awd里的pwn也是因为后门。。。逆向也是因为后门。。。

  • 如果是执行我所选用的find地址,执行结果为:

0000263700000026370000002637000000263700000026370000002637000000263700000026370000000000000000000000000000000000000000000000263700000026370000002637000000263700

  • 但是鉴于C语言里面 00002637与2637等值, 尽管程序可以通过执行并且输入十来个数进行check,如果对就返回flag。 但angr的执行结果返回了这么一堆带0的东西,而且没有分隔,这导致我不知道这十来个数到底是00002637还是2637或是26370之类的具体哪种或者哪几种。

  • 赛后复现题目的时候表哥给了个思路, find的地址直接取到后门的printf位置,这样便能直接输出flag!

  • 提供两个脚本,分别是windows版本的和Linux版本的。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #Windows
    import angr
    avoid = [0x40095B,0x400A98,0x400B16,0x400E6E,0x400EC2,0x400F70,0x401001]
    proj = angr.Project('D:\\CUBE',auto_load_libs = False)

    state = proj.factory.entry_state()

    simgr = proj.factory.simulation_manager(state)

    simgr.explore(find = 0x4010C1,avoid = avoid)

    #simgr.found[0].posix.dumps(0)

    print simgr.found[0].posix.dumps(1)

1
2
3
4
5
6
7
8
9
10
11
12
#Linux
import angr
avoid = [0x40095B,0x400A98,0x400B16,0x400E6E,0x400EC2,0x400F70,0x401001]
proj = angr.Project('./CUBE',auto_load_libs = False)

state = proj.factory.entry_state()

simgr = proj.factory.simulation_manager(state)

simgr.explore(find = 0x4010C1,avoid = avoid)

simgr.found[0].posix.dumps(1)
  • 运行得到flag:

skctf{2637002637000263700-26370026370002637002637002637000263700-2637002637000263700}

0x02 Fibonacci

  • IDA载入 来到main函数位置查看伪代码。
  • 提供两个方法。

方法一 算法逆向

  • 既然是Fibonacci,也就是斐波那契数列, 那么查看check函数。

  • 函数中 dword_60ACC0与 dword_60ACC4是我们输入的两个数。

  • dword_601080则是存放着斐波那契数列的一个数组。

  • 根据这个函数, 它遍历了从斐波那契数列第一个数到第五十个数,如果满足我们输入的两个数是斐波那契数列中相邻的两个数并且它们之和为75025,则成功输出flag。

  • 那么我们只需要先写出来一个长度为50的斐波那契数列,脚本如下:

1
2
3
4
5
6
# -*- coding: UTF-8 -*-
L = [1,1]
for i in range(48):
x = L[i]+L[i+1]
L.append(x)
print L
  • 结合斐波那契数列的性质, 我们输入的两个数相加一定会是斐波那契数列中的另一个数,并且在我们输入的这俩数中较大的一个数的后面。
  • 在输出的L里查找得到28657,46368,75025这一串,所以28657,46368即为答案。
  • 所以flag为:

SKCTF{2865746368}

方法二 angr

  • 由第一个CUBE题产生了灵感,直接angr。

  • 直接上脚本了, Windows的脚本。

1
2
3
4
5
6
7
8
9
10
11
import angr

proj = angr.Project('D:\\Fibonacci',auto_load_libs = False)

state = proj.factory.entry_state()

simgr = proj.factory.simulation_manager(state)

simgr.explore(find = 0x4008C4)

print simgr.found[0].posix.dumps(1)
  • 直接输出:

The flag is SKCTF{2865746368}

Pwn 部分

  • 但愿我能在这一部分更上一篇… 能力有限,还是先以逆向为主…