0%

刷题刷题

刷题刷题

考试结束,保研没着落,打工不想打,算法不想刷,学习不想学,进入自闭模式,重回buu,对一分题重拳出击(被一分题乱杀)
然后很多几十分的题就智障的不行。。。
buu有一点坑的就是题目描述上给了个链接,你也不知道这个题目给没给源码,有时候好像没给,一看就觉得题目太傻逼了,有时候事实上是给了的,不看源码自己就变成傻逼了

[HITCON 2016]Leaking

orange出的题,因为是很老的比赛了所以现在的参考价值不大了,大概一个限制了12字符长度的VM沙箱,然后flag是在沙箱外通过require config加载进来的,想拿flag要绕12字符的沙箱逃逸命令执行,看起来有点离谱
这里涉及到的是nodejs的远古内存分配问题,nodejs在远古版本(Node.js v5.4.1/v4.2.4)中的Buffer分配是就着以前用过的内存分配的,并且分配完了还不会初始化一下,也就意味着之前加载进内存然后被回收掉的内存位置可能被再次分配出来,并且还不会被初始化,原始数据还保留在那

这个外国大哥的文章讲了原理Node.js Buffer knows everything

Buffer objects, unlike TypedArrays, are not zero filled if created with a new Buffer(size) constructor (or its alias Buffer(size)). The memory that they use as the underlying storage could (and will) contain stuff that there was before the creation of this Buffer, most importantly — parts of other, previously used Buffer objects that were garbage collected.
Also it should be taken into an account that pretty much every standard I/O operation in Node.js uses Buffers — reading a file, requiring a module, receiving network traffic, passing stuff to the crypto module.

所以利用方案就是在那12个字符内直接Buffer(9999),把进程之前用过的内存都bababa倒出来,因为flag是require进来的,所以这个之前使用的内存也会在我们新开的buffer里面,直接在里面搜字符串获得flag
还有人用数组传参绕过了长度限制,数组长12第一个元素想写多长写多长

后来nodejs修了,buffer申请的时候都会自动初始化了,还给了一个Buffer.allocUnsafe函数来实现之前的分配buffer但是不初始化功能

所以这个题算沙箱逃逸吗?总觉得哪里怪怪的,还是说nodejs的沙箱实现和我的想象有点出入?

[FBCTF2019]Event

额,我觉得这个题有点脑洞,有点坑
登录,登录进去可以添加event,event应该是写了数据库的,有三个可控属性,name,addr和important,important选那个就会展示哪个,抓包改important会直接302重定向,有一个flag路由但是会显示你不是admin
翻一下cookie有一个叫user的,长得像jwt,base64解码第一段就是双引号包裹的用户名,估计伪造一下cookie就能拿flag
jwt解不出来,估计是flask的cookie,格式差不多

问题就在于怎么伪造,flask的cookie我只能想办法去拿key才行,试了下ssti,三个输入点都不行。。。
然后看wp,important那里有非常诡异的操作,你输个__dict__,他就会输出奇怪的东西出来了。。。
结果还是ssti,但是ssti的格式是他写好的,是0.<important>这么个形式,0就是当前这个SQL查询的结果。。。这也太难猜了
然后就是正常ssti流程,__init__.__globals__,本来想builtins一把梭,直接命令执行拉倒了,结果发现不知道为什么eval那里只要一加括号就会出错,然后吃到一个重定向
然后老老实实__init__.__globals__[app].config看密钥,然后去伪造一个名字叫"admin"的cookie,然后拿以前下下来的脚本跑还跑不通,报错
翻了一下脚本怎么写的,他是默认输入是json格式的,所以会对需要加密的对象先按json格式解析一下,这里确实有点诡异,他这的数据就是一个字符串,所以解析的时候就会出问题,直接把解析那步注释掉对着原始数据进行加密就行了,拿到伪造的user cookie访问flag路由获取flag

[PASECA2019]honey_shop

也是个flask cookie伪造,给了个文件下载,过滤了.py和.pyc后缀和flag.txt,本来想读/proc/self/fd,读了半天没读出来,难道python启动之后读自己本身这个脚本是不会保留在fd里面的吗?
然后就不知道读哪里了,功能点很有限,不像上个题能ssti,所以看wp
wp说可以读/proc/self/environ,这个里面放了当前进程的环境变量,里面有secret,是工程实现统一是这样的,还是因为题目动态部署的问题?以后没事就读一下这种东西,搞不好题目部署的时候把flag也写环境变量里面去了
读到了后面就都是简单东西了

[Zer0pts2020]phpNantokaAdmin

sqlite的注入题,不懂sqlite的神奇语法完全做不出来,学习了
晚点再搭个本地环境玩一下
看了半天源码,功能点就四个,创建数据库,插入数据,销毁数据库,查询整个数据库
销毁数据库没有用,查询数据库是直接select *的,且表名控制死了是用户创建的表,也没有用,插入数据用的prepare预处理,也不能用
只剩一个create,create的可控点还蛮多的,数据库名,列名,列的类型都可控,但是有一个waf,比较强力/[\"#'()*,\\/\\\\`-]/i,把单双引号反引号注释符小括号都干掉了,且限制了长度不超过32,SQL语句是这样的CREATE TABLE {\$table_name} (dummy1 TEXT, dummy2 TEXT,`$column` $type);,在create用户自定义的table之前,还创建了一个flag表插入了flag,但表名列名均未知
说实话也不知道怎么注入

然后看wp,然后发现这些操作我一个都不知道,然后从头来过

sqlite入门

先稍微入一下门再说吧。。。
本地搭一个环境,先来一个.header on.mode column,让输出能够看起来比较正常,不然默认的输出真是把人眼睛看瞎了
sqlite的命令都是以点开头的,什么.open <dbname>.quit之类的。。。
sqlite中有一个类似于mysql的information_schema的表,叫sqlite_master,记录了数据库表的一些信息,有这么五个字段type name tbl_name rootpage sql
type表示记录类型,重点是table,其余类型比如index,trigger之类的是主键触发器什么的,这里着重关注type为table时剩下列的意义
name就是表名,tbl_name在type是table时也是表名,rootpage表示存在哪一页(没什么意义),sql为创建这个记录时执行的sql语句

一般来说这里就是用来找表名的,同时还可以通过创建表时的SQL语句找到列名

sqlite的特殊引号

单引号,双引号,方括号,反引号
单引号表示括起来的是一个字符串
双引号,方括号及反引号均表示括起来的是标识符
方括号是为了兼容access和MSSQL,反引号是兼容MySQL,详见文档
sqlite文档

sqlite的奇怪性质

select <column_name> from <table_name>这样子的一个查询语句出现时,只要column_name是正确的,那么其后面就可以跟奇怪的垃圾数据而不影响查询结果,垃圾数据会被直接认为是当前这个列的一个别名

sqlite> select flag aaewqf23rf from test;
aaewqf23rf
----------
flag{test}
sqlite> select [flag]qwdef32r4 from test;
qwdef32r4 
----------
flag{test}
sqlite> select "flag"dqqfeq from test;
dqqfeq    
----------
flag{test}

以至于只需要闭合了引号,就算后面还有其他的引号也能正常使用

sqlite> select [flag][('ade"dqwq] from test;
('ade"dqwq
----------
flag{test}

create table as select

好吧,以前真没见过这个语法,并且这个语法好像mysql,sqlite,pgsql全都支持。。。
从字面上看大概也能猜出来在说什么,也就是用一个select语句的结果来创建一个新的表
说到这,这个题的解也就呼之欲出了

题解

create table处进行注入,并且和后面可控的type处里应外合,使用方括号对垃圾数据进行清理完成注入
拼出来的语句大概是这么个效果
create table [a] select sql[(dummy1 TEXT, dummy2 TEXT,`**a**` ]from sqlite_master);
加粗部分为用户输入,在tablename和type处整一堆方括号,就能把这堆垃圾数据变为sql列的别名,然后以这个数据创建出我们自己的数据库
获得flag表名列名后故技重施即可获得flag

这里的利用其实有一个小小的点,session中存的tablename并非我们之前创建数据库时所输入的tablename,而是通过查sqlite_master中不等于flag表表名的表名,这样才能把这个表名给取出来

参考链接

出题人的博客,不说中文看不懂啊。。。zer0pts CTF 2020 で出題した問題の解説
暗羽姐姐的中文译本phpNantokaAdmin – zer0pts CTF 2020

[羊城杯2020]easyphp

总觉得这个比赛我报名了的。。。是不是咕了?
简单的写文件,文件名限制在[a-z\.]没有斜杠所以不能目录穿越,写个php发现不能解析,估计是配置了就解析index.php,每次写文件之前会把当前目录下index.php文件以外的文件都删掉,所以也只能写一个,尝试覆盖index.php,没成功,那就只剩写htaccess了。
看内容里面file flag之类的过滤,看起来也觉得比较像写htaccess,并且最后还给文件里拼了一行垃圾

一行垃圾很好解决,htaccess经典操作之反斜杠转义换行符,注释去除单行垃圾。想起之前XNUCA的三行垃圾写htaccess,那个真是玄幻windows defender操作删除
关键字过滤也很简单,同样是反斜线转义换行符,中间插了个换行符也不影响解析
那么注释里面塞一个PHP语句然后php_value auto_append_file xxx就行,但是Apache默认配置看不到htaccess,这里想看一下写进去的东西是什么,浪费了半天。。。
什么Require all granted,Allow from all都上了,不太好用,最后试了一句Satisfy Any,看得见htaccess内容了
本来想直接把htaccess当PHP处理,塞了句SetHandler application x-httpd-php上去,本地是跑通了,远程没跑通,估计是配置了只解析index.php的配置不是用这句覆盖的?

还有一个坑点,auto_append_file,本地后面的路径直接写绝对相对都跑的通,远程环境要加一个引号把路径括起来才能

[羊城杯2020]easyphp2

emmm,先上来给一个很明显的文件包含,读了一下发现/etc/passwd发现没拼目录,试了下伪协议,有waf,把base64,rot13什么的都给ban了(这里记一下rot13的用法是string.rot13)
然后是喜闻乐见的二次编码绕过,我把这茬给忘了。。。只要能用伪协议应该就能二次编码绕过吧,这是伪协议在底层处理的时候对过滤器进行了额外的url解码导致的,所以之前有一次比赛把php ban了就不能二次编码绕过
读源码,不知道为什么index.php就是读不到?把这个GWHT.php读了,要先给一个ENV里面的PASS,然后后面有一个命令执行,这个有点坑,读/proc/self/environ读不出来,不知道pass去哪找,结果看wp是robots.txt里面有一个提示,读了之后就能看到pass是GWHT。。。。虽然有直接猜出来的可能,但是还是想吐槽这个点好坑
命令执行大概就是exec("printf '$content'|wc -c"),exec的话命令执行结果是在返回值里面,并且还整了个wc,就等于是个无回显命令执行呗,过滤了分号<?php这些没什么用的东西,直接把单引号一闭合反引号命令执行就是了,很简单的.jpg
无回显就把结果写到文件里,不知道能不能弹shell因为一开始写了个ini_set('max_execution_time', 5);,索性再写一个shell弹回来就是了,写的时候注意各种引号直接的关系和转义$,单行的PHP也不需要分号,短标签过<?php的waf,这里明明写进去的文件权限是644,但是我却不能追加写入,很诡异嗷,不然也可以追加写入过waf
'`echo%20"<?=eval(\\$_REQUEST[a])?>"%20>test1.php`'
然后蚁剑连上去方便一点,根目录有一个GWHT文件夹,里面一堆垃圾空文件夹,有一个目录下面有flag,但是是root:GWHT 440权限,GWHT文件夹里面有一个README给了密码的hash,但是cmd5查出来告诉你是收费记录。emmm,看wp,是GWHTCTF,蚁剑的虚拟终端其实是通过命令执行然后打印出来的,所以还要再自己弹一个交互式的shell回来,登录GWHT用户,拿到flag