PHP代码审计基础
最后更新于
最后更新于
将下载好的VAuditDemo_Debug
目录复制到phpstudy
的www
目录下,然后将其文件名字修改成VAuditDemo
,当然你也可以修改成其他的
运行phpstudy并且访问install目录下的install.php
,这里我访问的是http://127.0.0.1/VAuditDemo/install/install.php
查看以上服务是否支持后点击安装,数据库的默认账户密码均为root
打开phpstudy修改网页站点域名, 修改网站目录为靶场文件目录, 修改网站端口为88
端口
重启phpstudy后访问127.0.0.1:88
, 出现如下页面代表搭建成功
设置为on
时,php会将$_POST,$_GET,$_COOKIE
,$_ENV
,$_SESSION
直接注册成全局变量,例如$_POST['user']
会注册成$user
因此要将此选项设置成off
决定是否允许php开启缩写形式(<? ?>
),本指令也会影响到缩写形式<?=
,它和<? echo
等价,例如下图所示
php的安全模式能针对php中的一些函数作权限控制,例如system()
,但是默认的php.ini是没有打开的,安全模式从5.4.0已被移除
禁用某些类以及函数,接受逗号分隔的函数名列表作为参数
上传设置及上传文件大小
文件上传临时目录
如果没设置,则采用系统临时目录(/tmp
,c://windows/tmp
)
用户访问目录限制
该设置可以控制php脚本只能访问指定目录,从而在一定程度上限制了webshell的危害。一般设置成只能访问网站目录或者临时目录,从而有效防止webshell跨站执行
错误信息控制
将错误信息输出,站点发布后应该关闭此功能
设置错误报告级别
这个设置的作用是将错误级别设置为最高,利用写出高质量代码
错误日志
魔术引号
设置为on时开启自动转义功能,将单引号,双引号,反斜杠等等转义掉
是否允许打开远程文件
本选项激活了url形式的fopen封装协议使得可以访问url对象例如文件。默认的封装协议提供用ftp和http协议来访问远程文件。一般开启后配合文件包含函数可使用伪协议进行攻击
是否允许包含远程文件
本选项激活允许include
、include_once、require
、require_once
等函数使用url形式的fopen封装协议,会造成远程包含漏洞
eval()
assert()
判断语句逻辑是否为真,为假则返回false,但还是会执行代码,常被利用到制作免杀webshell
preg_replace()
参数一为正则表达式,依照 php的格式,表达式在两个/
之间,如果在表达式末尾加上一个 e
,则参数二就会被当做 php代码执行
注意: 参数二需要在正则匹配成功后才能执行
create_function()
创建一个匿名函数给test变量, 此变量可调用匿名函数, 参数一为匿名函数的参数, 参数二为匿名函数的执行代码
call_user_func()
调用函数,参数一为被调函数名,参数二为被调用函数的参数
require
、include
、require_once
、include_once
。
Exec()
、passthru()
、proc_open()
、shell_exec()
、system()
、popen()
读取可以读取配置信息,写入可以写入shell,删除可以删除.lock文件实现重新覆盖
信息泄露
软连接-读取文件内容(linux生效)
环境变量
配置函数
数字判断函数
变量覆盖
输出当前目录文件
无参数获取信息
无验证功能,任意重装覆盖
$_GET[‘step’]跳过限制步骤
变量覆盖导致重装
判断lock后跳转无exit
解析install.php.bak漏洞
分析install目录下的install.php
文件,判断lock文件后是否执行exit
函数
追踪变量,发现$str_tmp
变量写入到config.php
文件中
寻找$str_tmp
变量的可控点,最后发现$dbname
变量参与了$str_tmp
变量值的生成
进入config.php
文件,发现$dbname
变量的值赋给了$database
变量
在install.php
页面构造php代码注入,exp如下所示
利用此exp能够组成含有注入的变量,如下
system()
exec()
passthru()
shell_exec()
ctrl+F
追踪危险函数所涉及到的页面以及变量
全局搜索危险函数及其所在文件,发现ping.php
包含危险函数
跳转到ping.php
文件,发现$cmd
变量与危险函数shell_exec
有关联, $cmd
值的组成与$target
有关联
$target
变量是可控的,也就是说可以在$target
写入payload
网站转到ping.php
页面, 输入127.0.0.1 | whoami
, 构成命令执行注入
采用filter_var()
函数来判断变量是否是标准的ip格式
echo file_get_contents()
readfile()
全局搜索文件读取函数,在user/avatar.php
发现file_get_contents()
函数以及其关联变量$_SESSION['avatar']
全局搜索$_SESSION[‘avatar’]
,发现在user/logCheck.php
存在此函数, 并且发现$row['user_avatar']
构成了此变量,
全局搜索user_avatar
字段, 发现其在user/updateAvatar.php
文件中, user_avatar
由$avatar
组成的, 而$avatar
是可控的, 其值由文件上传的名字和其他字符所组成, 也就是说可以在上传的文件名里构造payload
如果上传的文件名为',user_avatar = '../sys/config.php'#.png
,那么$avatar的值为../uploads/u_11111_',user_avatar = '../sys/config.php'#.png
构造的sql语句为UPDATE users SET user_avatar = '../uploads/u_11111_',user_avatar = '../sys/config.php'#.png' WHERE user_name='{$_SESSION['user_id']}'
在update语句中SET最后一个字段名才生效, 还有mysql插入数据字段值时会自动除去反斜杠 ,因此把配置文件路径改成16进制, 最终上传的文件名字为: ',user_avatar = 0x2E2E2F7379732F636F6E6669672E706870#.png
通过以上对代码的审计, 确定了漏洞利用的页面有3个,先后顺序分别是updateAvatar.php
、logcheck.php
、avatar.php
在updateavatar.php
页面上传图片并修改文件名,然后查看数据库表的字段值,发现其被修改成配置文件的路径
随后依次访问logcheck.php
,avatar.php
echo
追踪echo函数寻找可控点,在admin/manageUser.php
发现一处输出用户ip: echo $users['login_ip']
追踪login_ip
字段名,在admin/logCheck.php
发现其涉及两个函数, 分别是get_client_ip()
、sqlwaf()
追踪get_client_ip()
、sqlwaf()
,跳转到其代码定义处lib.php
,发现可以通过伪造ip进行xss注入攻击
在logcheck.php
页面伪造ip,修改x-forwarded-for
的值为xss语句,随后登录账号
xss语句也成功插入了数据库,且管理员访问mange.php页面也触发了xss攻击
xss接收平台也收到了管理员的cookie信息
登录爆破漏洞是属于撞库的一种,爆破账号密码时要考虑是否需要输入验证码,若需要输入验证码,则从绕过验证码入手
从登录页面logCheck.php
开始分析
追踪$_session['captcha']
,在admin/captcha.php
找到生成验证码的代码, 发现其采用的是随机数机制
若想要$_session['captcha']
值为空,只需清空cookie即可
burpsuite抓包logCheck.php
,清空cookie值, 将验证码的post数据更改为空, 随后进行爆破
在登录页面的验证代码处添加判断验证码是否为空的代码
可以操作(更改、删除、添加等)用户的信息
通常越权漏洞存在于涉及用户操作的页面, 例如修改密码, 更新用户数据等等, 此处转到更改用户名字页面updateName.php
发现$_POST['id']
是可控的, 也就说如果我们把ID修改成别人的, 那么相当于把别人的账号给覆盖了
点击更新用户名抓包,修改post数据里的id
值
将ID参数设置成不可控,将ID设置成session['user_id']变量,即代表当前登录账号的ID
对于PHP magic_quotes_gpc=on
的情况, 我们可以不对输入和输出数据库的字符串数据作addslashes()
和stripslashes()
的操作,数据也会正常显示, stripslashes()的作用是删除addslashes()
函数添加的反斜杠
在messageSub.php
文件发现一处可能存在sql注入的查询语句,SESSION['username']
和$_POST['message']
这两个变量虽然经过魔术引号过滤, 但是依然是可控的, 接下来就寻找给这两个变量赋值的地方
通过字符串搜索SESSION['username']
, 在登录检验界面logCheck.php
发现SESSION['username']
的值来源于 $row['user_name']
变量,而这个$row['user_name']
是数据库中列名为user_name
的值,接下来追踪在哪处给数据库插入user_name
的值
在用户注册页面updateName.php
页面设置了数据库中列名为user_name
的值, 可在注册用户名框插入sql注入语句,现在我们找到了构造SESSION['username']
变量的地方,接着寻找构造$_POST['message']
的地方
查看留言页面message.php
,此处有个表单上传的html, 将$_POST['message']
的值提交到messageSub.php
, 由此可知$_POST['message']
的值是留言的内容, 在留言内容框注入sql注入语句
1.在用户注册页面插入payload: kkk\
注册后记得要重新登陆, 因为要刷新下$_SESSION['username']
的值
通过查询数据库的user表发现user_name
的值为kkk\
,这是因为魔术引号的过滤所导致
在注册kkk\
这个账号的同时查看mysql监控, 经过转义后插入数据库的值为kkk\
2.在用户留言处插入payload:,(select admin_pass from admin limit 0,1),1);#
sql注入后会显示md5加密后的用户密码
在留言处插入sql语句后查看mysql监控,可知此处执行的sql语句是:INSERT INTO comment(user_name,comment_text,pub_date) VALUES ('kkk\',',(select admin_pass from admin limit 0,1),1);#',now())
真正执行的sql语句是:INSERT INTO comment(user_name,comment_text,pub_date) VALUES ('kkk\',',(select admin_pass from admin limit 0,1),1);#
在regCheck.php
和updateName.php
插入正则表达式来排除非数字字母字符
函数 | 作用 |
---|---|