上一周SYSU网络安全学院的CTF战队“咏春”组织了招新赛
本篇文章就来分享一下本人在这次招新赛中的收获
本人是刚入门CTF的小萌新,所以只能挑挑其中比较容易的题练手
也算是幸运,趁着大佬们在攻克Pwn和Reverse的时侯,抢了两道Misc的一血和两道Crypto的一血
在最后混到第4的排名
那么这篇文章会分记录这次比赛中本人解出来的且比较具有代表性的题目,并把每一题分为两个部分:第一个部分会分享本人在解题时的心路历程以及题目的write up;第二部分会谈谈本人在解题时学到的知识,以及一些工具的用法。
链接:https://pan.baidu.com/s/1eIq3EHbB07gGkD_8cW9prg?pwd=Rick
提取码:Rick
–来自百度网盘超级会员V3的分享
题目给的附件如下图
看到.vmdk后缀的文件,我首先想到的是能不能用vmware虚拟机将其打开。
但是在报错之后我觉得这题并没有那么简单。
看到题目描述里的“真真假假”时,我猜这个文件用常规的虚拟机是打不开的。
于是将其改为txt后缀并打开,翻到最后发现了一些有关flag的信息:
flag{hahaha_1ts_4_Fake_f1a9}flag{hahaha_1ts_4_Fake_f1a9}flag{hahaha_1ts_4_Fake_f1a9}flag{hahaha_1ts_4_Fake_f1a9}flag{hahaha_1ts_4_Fake_f1a9}flag{hahaha_1ts_4_Fake_f1a9}flag{hahaha_1ts_4_Fake_f1a9}flag{hahaha_1ts_4_Fake_f1a9}flag{hahaha_1ts_4_Fake_f1a9}flag{hahaha_1ts_4_Fake_f1a9}flag{hahaha_1ts_4_Fake_f1a9}flag{hahaha_1ts_4_Fake_f1a9}flag{hahaha_1ts_4_Fake_f1a9}flag{hahaha_1ts_4_Fake_f1a9}flag{hahaha_1ts_4_Fake_f1a9}flag{hahaha_1ts_4_Fake_f1a9}flag{hahaha_1ts_4_Fake_f1a9}flag{hahaha_1ts_4_Fake_f1a9}flag{hahaha_1ts_4_Fake_f1a9}flag{hahaha_1ts_4_Fake_f1a9}flag{hahaha_1ts_4_Fake_f1a9}flag{hahaha_1ts_4_Fake_f1a9}flag{hahaha_1ts_4_Fake_f1a9}flag{hahaha_1ts_4_Fake_f1a9}flag{hahaha_1ts_4_Fake_f1a9}flag{hahaha_1ts_4_Fake_f1a9}flag{hahaha_1ts_4_Fake_f1a9}flag{hahaha_1ts_4_Fake_f1a9}flag{hahaha_1ts_4_Fake_f1a9}flag{hahaha_1ts_4_Fake_f1a9}and_Y0U_F1nd}}
可以发现有and_YOU_F1nd}
这种极具语义的信息,推测其为flag的后半部分
结合题目中的“分分合合”一词,推测要将vmdk文件分解,于是将其丢入7zip里解压缩
得到如下几个文件:
打开FLAG,可以得到flag的前半部分:flag{7z1p_1s_pvverfu1_
本题运用到了工具7-Zip,正如flag所说,7-Zip在压缩和解压缩的功能上还是非常强大的
小知识点:
该题给出的图片直接展示出flag的上半部分,结合语义,考虑图片隐写中png格式图片的IHDR问题
使用010 Editor将png图片打开如下图
在文件头中找到IHDR,即16进制49 48 44 52
,修改其后的图片宽度00 00 01 0E
和图片高度00 00 00 1E
将图片高度改为00 00 02 6E
后可得到完整图片如下:
故本题的flag为flag{where_is_my_body_BBBB_OOOO_DDDD_YYYY}
首先本题用到了一款非常强大的16进制编辑器软件010 Editor。听战队里的前辈yh说,在做misc题时,经常会用到这款软件,同时其在将16进制与其他格式如二进制、文本相互转换时非常方便。
在这里贴一个大佬写的 010 Editor的进阶用法链接:
最好用的十六进制编辑器 010 Editor
做ctf的misc题需要对各种格式的文件的16进制编码有影响,这样在不提供后缀时能第一时间反应到是什么格式的文件。
这里贴一个png文件格式的详解链接:
PNG文件格式详解
本题为一道非常基础的社工题
初步观察给出的图片可得出其为jpg格式的信息,所以先把图片用exiftool分析一下
由 Date Original可知该照片于2022年7月8日拍摄,但是解析出的exif数据中并没有GPS经纬度信息
接下来看题目描述:
“在干啥呢,赶紧回来出题。” “恰拉面。” “偷偷溜出去恰拉面还不叫上我?小心我开你盒!” “开盒有啥意思,来玩点有意思的” 请问2019年10月拉面店门前大路的报亭的广告上的人的生日是什么时候(格式:YYYY_MM_DD)
结合题目描述中2019年10月
可知,该图片仅仅是用来定位拉面店地点,而报亭地址信息也只有在先锁定了拉面店再于附近寻找,无法从附件图片中直接得出。
首先google店名“一龙拉面”可知,其为开设在广州的连锁店,一共有五家。
通过分析美食博主在小红书、大众点评等app上的种草图片可知,**一龍拉面·冲绳首里城旗舰店(天河南店)**符合图中的装修风格。
于是可以祭出社工神器Google地图以及其街景功能,但是由于地点是在国内,所以只能退而求其次,使用百度地图的街景
在门口的大路上搜寻,正好找到下图的报刊亭,结合街景拍摄时间2020,基本上与答案八九不离十了
国内的朋友应该对这个主持人不陌生,而如果你觉得很面生,可以百度一下海报广告中的内容,无非是多几分钟的搜索时间。
这里就不把人名和flag贴出来了。
Exif是可交换图像文件格式(Exchangeable image file format),是一种标准,定义了与数码相机捕获的图像(或其他媒体)有关的信息,用于存储重要的数据,比如相机的曝光、拍摄日期和时间,甚至GPS定位等。
Exif可以附加于 JPEG 、 TIFF 、 RIFF 等文件之中,为其增加有关数码相机拍摄信息的内容和索引图或图像处理软件的版本信息。
本题运用到的工具是exiftool,在社工题中用处很大,而且在解析图片信息时也有妙用。
其实在kali里面也整合了exiftool的功能,同样是通过命令行实现,但是因为本题大部分工作是搜索,在电脑主机上进行比较方便,所以我索性就用win版本的exiftool了。
收到的题目附件中一共有两个文件
先从提示hint.py看起:
import base64
import string
str1 = "something you don't know"
newtable = "QmWnE01bR2vT98cY75xUzI6aO4sPdLfKgJhH3jGkFlDpSoAiZ+uXyCtVrBeN/wMq"
table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
str2 = base64.b64encode(str1.encode()).decode()
print(str2)
print(str2.translate(str.maketrans(newtable,table)))
快速浏览一遍,发现是某种加密方式,那么flag.txt估计就是密文了
果然flag.txt中内容wBSiwk2w+o3eAFoYzF7V7ERjI3MTsE3e3qI1+T3e+EweAlAGILPFeA==
为base64编码
通过查阅python中的translate函数可知其作用是将str2中的字符从table映射至newtable
理解了加密方法,那么写出解密脚本就不是问题了,只需将密文的字符映射回来并base64解码:即将table与newtable调换位置,并将密文的值附给str1,最后使用base64中自带的b64decode解码。
解题脚本如下
import base64
import string
str1 = "wBSiwk2w+o3eAFoYzF7V7ERjI3MTsE3e3qI1+T3e+EweAlAGILPFeA=="
newtable = "QmWnE01bR2vT98cY75xUzI6aO4sPdLfKgJhH3jGkFlDpSoAiZ+uXyCtVrBeN/wMq"
table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
str2 = str1.translate(str.maketrans(table,newtable))
print(base64.b64decode(str2))
解得flag为flag{Y0U_CAN_CH4NGE_THE_T4B1E_0F_B45E64}
注:两个字符串的长度必须相同,为一一对应的关系。
str.maketrans(intab, outtab)
参数
intab – 字符串中要替代的字符组成的字符串。
outtab – 相应的映射字符的字符串。
translate() 方法根据参数 table 给出的表(包含 256 个字符)转换字符串的字符,要过滤掉的字符放到 deletechars 参数中。
translate()方法语法:
str.translate(table)
bytes.translate(table[, delete])
bytearray.translate(table[, delete])
参数
table – 翻译表,翻译表是通过 maketrans() 方法转换而来。
deletechars – 字符串中要过滤的字符列表。
返回值:返回翻译后的字符串,若给出了 delete 参数,则将原来的bytes中的属于delete的字符删除,剩下的字符要按照table中给出的映射来进行映射 。
看到题目中的ntrue就知道,这题应该与ntru格密码有关,那么ezNTRUE应该就是简单版咯,果不其然,学过《信息安全数学基础》这门课程就能将这题秒杀
附件中task.py代码如下:
from Crypto.Util.number import *
from secret import flag
def gen(p, q, fbits, gbits):
f = getPrime(fbits)
g = getRandomNBitInteger(gbits)
fp = pow(f, -1, p)
fq = pow(f, -1, q)
h = p * fq * g % q
pub = h
pri = (f, fp)
return pub, pri
def encrypt(pub, msg):
h = pub
r = getRandomNBitInteger(32)
c = r * h + msg
return c
fbits = 114
pbits = 514
qbits = 1919
gbits = 810
p = getPrime(pbits)
q = getRandomNBitInteger(qbits)
assert p < q
pub, pri = gen(p, q, fbits, gbits)
m = bytes_to_long(flag)
c = encrypt(pub, m)
print(f'p = {p}')
print(f'q = {q}')
print(f'pri = {pri}')
print(f'c = {c}')
输出output.txt内容如下:
p = 39696534708331497478078596949366551254458039906487063274519365557503525568966838603935883232293659554463107770308640259644533280664672534779600517649986059
q = 33845587450234387218683746145498488763698598229278276480458546928792339413769968077853526645950302533020194391650117905478087009591432416950736817012782717651336179207922943604296994050726509520053392703504721556619358895593098766009189861461947552976772454710544452208851897026895605248153578197013401411186916307408137513611146508413930414959309967905013809506695114035797439887986570609411887830819442498398343409098218109885525690946454737438608201754973097641820502436357029642135534233478940863384269857217395902679475540558919784564731798673197560087193097336780962879716
pri = (19865770721277618181876567504573333, 5489494441670054142937588114066774435471342108150158539209487762555020100543649641623797293358973310052946362271598968380588976187388814840494849823235305)
c = 53484871684975510809035045015775716498630895031029420037931060425708077051766065196920378110070387085519970158412204703986166126850226340099542405919853227775557183379431305778161817609150453505160858758972423992960925238580489233002719593829791807355167703736238566049294585651447631831076944446098692856797269525180505699282387563436841786837418375970556732852165591080721561888008116655275004997201356117473364059245846926508162387834931594057871475945194235459090643448870546189680276607867469805540458113547484179203670555638634018105999735351008081376754952824903738495151081874205
题目中泄露了私钥,如果已知公钥h
的值,在比特长度合适的情况下可以利用最短向量规约解决。但是这里并未给出h
的值。已知的条件有:
f p ⋅ f ≡ 1 ( m o d p ) f q ⋅ f ≡ 1 ( m o d p ) h ≡ p ⋅ f q ⋅ g ( m o d q ) f_p\cdot f\equiv 1 (\bmod p) \\ f_q\cdot f\equiv 1 (\bmod p) \\ h \equiv p\cdot f_q\cdot g(\bmod q) fp⋅f≡1(modp)fq⋅f≡1(modp)h≡p⋅fq⋅g(modq)
密文c=r*h+m
,r
是未知的32位随机数。已知f
,推导:
c ⋅ f ⋅ f p ≡ r ⋅ p ⋅ f q ⋅ g ⋅ f ⋅ f p + m ⋅ f ⋅ f p ≡ m ( m o d p ) c\cdot f\cdot f_p \equiv r \cdot p\cdot f_q\cdot g \cdot f \cdot f_p + m\cdot f \cdot f_p \equiv m(\bmod p) \\ c⋅f⋅fp≡r⋅p⋅fq⋅g⋅f⋅fp+m⋅f⋅fp≡m(modp)
可写出如下解题脚本:
from Crypto.Util.number import *
p = 39696534708331497478078596949366551254458039906487063274519365557503525568966838603935883232293659554463107770308640259644533280664672534779600517649986059
q = 33845587450234387218683746145498488763698598229278276480458546928792339413769968077853526645950302533020194391650117905478087009591432416950736817012782717651336179207922943604296994050726509520053392703504721556619358895593098766009189861461947552976772454710544452208851897026895605248153578197013401411186916307408137513611146508413930414959309967905013809506695114035797439887986570609411887830819442498398343409098218109885525690946454737438608201754973097641820502436357029642135534233478940863384269857217395902679475540558919784564731798673197560087193097336780962879716
f, fp = (19865770721277618181876567504573333, 5489494441670054142937588114066774435471342108150158539209487762555020100543649641623797293358973310052946362271598968380588976187388814840494849823235305)
c = 53484871684975510809035045015775716498630895031029420037931060425708077051766065196920378110070387085519970158412204703986166126850226340099542405919853227775557183379431305778161817609150453505160858758972423992960925238580489233002719593829791807355167703736238566049294585651447631831076944446098692856797269525180505699282387563436841786837418375970556732852165591080721561888008116655275004997201356117473364059245846926508162387834931594057871475945194235459090643448870546189680276607867469805540458113547484179203670555638634018105999735351008081376754952824903738495151081874205
a = (c * f) % q
m = (a * fp) % p
print(long_to_bytes(m))
解得flag为flag{7cb5533c-62a1-11ed-b271-00155deaa0c6}
对于初探Crypto类型题目的人(比如我QAQ)来说,理解题目的代码结构非常重要,而Crypto.Util.number
是出现频次非常高的一个函数库模块
在这里列出一个大佬整理的笔记:
NTRU-密码学
有关ntru的进阶Crypto题目(相对于本题来说要难得多):
从一道CTF题初探NTRU格密码 - 先知社区 (aliyun.com)
还未打开附件时,我就意识到这题应该是考的AES加密,如果是babyAES,那一定很简单吧(坏笑.jpg)
题目所给附件chall.py代码如下
from Crypto.Cipher import AES
from secret import flag
key = b'I have practiced for 2.5 years!!'
iv = ???
def pad(s):
return s + (16 - len(s) % 16) * b'\0'
def xor(a, b):
return bytes([x ^ y for x, y in zip(a, b)])
aes = AES.new(key, AES.MODE_CBC, iv)
cipher = aes.encrypt(pad(flag)).hex()
hint = xor(key, iv).hex()
print(f'cipher = {cipher}')
print(f'hint = {hint}')
# cipher = 32a29b99cc0ab09329dcf199a2c0044daff1f5ea686545b1dacbcf4ff8ebd87b75b6e7d5b6c61f5ddb45330bbf36aa66
# hint = 08520d410f0a5550130f431d02160b5b
首先快速浏览一遍代码
偏移量iv是AES加密中非常重要的元素
看到xor函数,发现这题可能用到了异或的性质,于是以这一点为突破口来理解加密方式
结合题目所给条件,利用hint和key可以通过异或运算算出iv
接着发现原来cipher就是flag扩增后AES加密得到的密文,那么本题可以直接用到AES模块中的aes.decrypt()
函数进行解密
于是可以写出如下解题脚本:
import binascii
from Crypto.Cipher import AES
import sys
hint =binascii.a2b_hex(b'08520d410f0a5550130f431d02160b5b')
key = b'I have practiced for 2.5 years!!'
def xor(a, b):
return bytes([x ^ y for x, y in zip(a, b)])
iv =xor(hint,key)#使用xor还原出iv
#iv=b'Are you an ikun?'
print(sys.getsizeof(iv))#验证iv的bite长度是否为16的倍数
print(iv)
aes = AES.new(key,AES.MODE_CBC,iv)
cipher = b'32a29b99cc0ab09329dcf199a2c0044daff1f5ea686545b1dacbcf4ff8ebd87b75b6e7d5b6c61f5ddb45330bbf36aa66'
pad = aes.decrypt(binascii.a2b_hex(cipher)) #这里用a2b_hex函数把cipher还原成字符串
print(pad)#输出的pad中还包含补全的\x00
解得pad为b'flag{bca16c94-6713-11ed-83ea-00155d079966}\x00\x00\x00\x00\x00\x00'
那么flag便是除去\x00后的flag{bca16c94-6713-11ed-83ea-00155d079966}
(哼,小黑子)
学习嘛,总归是一个不断去搜索,不断自己去看的过程。所以这里就不喂现成的给你了。
甩一个大佬的详解链接:
AES加密算法的详细介绍与实现
下面这题可能很臭,提前画一条分界线(其实ezNTRUE这题就很臭了hhh)
看到这里你一定会忍不住吐槽,凯撒密码多简单啊,值得挑出来讲吗?但是非也非也,这题还结合了更多元素,我觉得是拓展我们黑客发散性思维的好题(悲)
首先附件所给文件的标题就非常劲爆
一般来说凯撒密码题的变种都是偏移量有一定规律,那么这个114514
很有可能就是hint了
打开之后得到密文:gmel_omkzydpr_tbm_lbovtin_eitv
将前几个字母与flag比对后发现,偏移量分别为"-1,-1,-4,-5"那么这题的偏移量估计就是114514的循环了
而这个_符号要便宜到{,那么就会打破114514的魔咒(悲),所以我猜这题并没有将凯撒密码扩展到ASCII码表上
于是将_符合全部抽离,并进行解密
随便写个C++的解题脚本(喜)
#include
#include
using namespace std;
string s1="gmelomkzydprtbmlbovtineitv";
int add[6]={-1,-1,-4,-5,-1,-4};
int main()
{
int tag=0;
for(int i=0;i=6)
tag=0;
}
cout<
运行得到flagnijyuyonsaigakuseidesu
此时你会感到疑惑,会不会算法错了?
我们又想到之前舍弃的_符号,会不会它是语义标签呢,遂加上
得到 flag_nijyuyon_sai_gakusei_desu
百度一下,发现居然是一句日语,“二十四岁是学生”,至于出题人为什么要这样出题,我们也不得而知(恼)
那么flag应该就是flag{nijyuyon_sai_gakusei_desu}
(可恶啊,这题出的真的nt,我一开始纠结了半天第一个_是不是也要放在{}里,导致我错失了一血)
114514
甩一个链接给你,快去补课吧
这次比赛中,Reverse里有几道西电Moe原题,我就不贴出来了,写写其他比较有意思的题
附件给的是exe文件如下图
直接把它丢到ida里先f5一下(不得不说ida真是反编译神器啊,我一定买的是正版,是?吧?)
得到如下代码
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v4[32]; // [rsp+20h] [rbp-90h] BYREF
int v5[24]; // [rsp+40h] [rbp-70h]
int v6; // [rsp+A0h] [rbp-10h]
int v7; // [rsp+A4h] [rbp-Ch]
int i; // [rsp+A8h] [rbp-8h]
int v9; // [rsp+ACh] [rbp-4h]
_main();
v5[0] = 102;
v5[1] = 198;
v5[2] = 22;
v5[3] = 118;
v5[4] = 183;
v5[5] = 69;
v5[6] = 134;
v5[7] = 150;
v5[8] = 55;
v5[9] = 245;
v5[10] = 19;
v5[11] = 55;
v5[12] = 245;
v5[13] = 163;
v5[14] = 146;
v5[15] = 245;
v5[16] = 102;
v5[17] = 87;
v5[18] = 230;
v5[19] = 230;
v5[20] = 151;
v5[21] = 215;
puts("int ppppppputtttttt your flag,and i will reverse it!");
scanf("%s", v4);
v9 = 0;
for ( i = 0; i <= 21; ++i )
{
v7 = (unsigned __int8)(16 * v4[i]);
v6 = v4[i] >> 4;
if ( (v6 | v7) == v5[i] )
++v9;
}
if ( v9 == 22 )
printf("TTTTTTTTTTTQQQQQQQQLLLLLLLLLL!!!!!");
else
printf("it is a pity ~_~");
return 0;
}
根据题目给的加密方式,遍历字符表暴力解密,稍微修改原代码得如下解题脚本:
#include
#include
int main()
{ int v6,v7,i;
int v4;
int v5[22];
v5[0] = 102;
v5[1] = 198;
v5[2] = 22;
v5[3] = 118;
v5[4] = 183;
v5[5] = 69;
v5[6] = 134;
v5[7] = 150;
v5[8] = 55;
v5[9] = 245;
v5[10] = 19;
v5[11] = 55;
v5[12] = 245;
v5[13] = 163;
v5[14] = 146;
v5[15] = 245;
v5[16] = 102;
v5[17] = 87;
v5[18] = 230;
v5[19] = 230;
v5[20] = 151;
v5[21] = 215;
for (i = 0; i <= 21; ++i )
{
for(v4=33;v4<127;v4++)
{
v7 = (unsigned __int8)(16 * v4);
v6 = v4 >> 4;
if ( (v6 | v7) == v5[i] )
printf("%c",v4);
}
}
}
得出flag为flag{This_1s_:)_funny}
ida可谓是Reverse题的神器,在这里就贴一个下载链接吧:既然你贵的不仁,那我也不义(开玩笑,有钱还请支持正版)
看到这题名字你应该大概知道该怎么解了
先把Xor.exe丢进ida并f5一下
得到如下代码
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v4[32]; // [rsp+20h] [rbp-C0h]
char v5[32]; // [rsp+40h] [rbp-A0h] BYREF
int v6[29]; // [rsp+60h] [rbp-80h]
int j; // [rsp+D4h] [rbp-Ch]
int i; // [rsp+D8h] [rbp-8h]
int v9; // [rsp+DCh] [rbp-4h]
_main();
puts("In put your flag,and i will check for you");
v6[0] = 102;
v6[1] = 109;
v6[2] = 99;
v6[3] = 100;
v6[4] = 127;
v6[5] = 93;
v6[6] = 54;
v6[7] = 117;
v6[8] = 87;
v6[9] = 56;
v6[10] = 121;
v6[11] = 84;
v6[12] = 127;
v6[13] = 98;
v6[14] = 81;
v6[15] = 62;
v6[16] = 126;
v6[17] = 118;
v6[18] = 102;
v6[19] = 118;
v6[20] = 102;
v6[21] = 112;
v6[22] = 101;
v6[23] = 99;
v6[24] = 113;
v6[25] = 119;
v6[26] = 35;
v6[27] = 101;
v6[28] = 97;
scanf_s("%s", v5);
v9 = 0;
for ( i = 0; i <= 28; ++i )
v4[i] = v5[i] ^ i;
for ( j = 0; j <= 28; ++j )
{
if ( v4[j] == v6[j] )
++v9;
}
if ( v9 == 29 )
printf("Yessssssss");
else
printf("Try again!");
return 0;
}
利用Xor的性质,可将密文与密钥异或得到明文,这题密钥就是数组括号内数字,解题脚本如下:
clude<math.h>
int main()
{ char v5[32];
int i;
int v6[29];
v6[0] = 102;
v6[1] = 109;
v6[2] = 99;
v6[3] = 100;
v6[4] = 127;
v6[5] = 93;
v6[6] = 54;
v6[7] = 117;
v6[8] = 87;
v6[9] = 56;
v6[10] = 121;
v6[11] = 84;
v6[12] = 127;
v6[13] = 98;
v6[14] = 81;
v6[15] = 62;
v6[16] = 126;
v6[17] = 118;
v6[18] = 102;
v6[19] = 118;
v6[20] = 102;
v6[21] = 112;
v6[22] = 101;
v6[23] = 99;
v6[24] = 113;
v6[25] = 119;
v6[26] = 35;
v6[27] = 101;
v6[28] = 97;
for(i = 0;i<= 28;++i)
v5[i] = v6[i] ^ i;
printf("%s",v5);
}
解得flag为flag{X0r_1s_so_1ngterestin9~}
明文^密钥=密文;
密文^密钥=明文
异或运算的特性:
1: a^b=c;当c异或b时,结果还原成a
2:一个数异或自己时等于0;
3:一个数异或0的时候,结果是其本身
4:交换律: A ^ B = B ^ A
5:结合律: ( A ^ B ) ^ C = A ^ ( B ^ C )
web这回没啥难的题,就记录一题当作php的学习了
打开所给域名后得到如下php代码
理解完代码发现这题给我们提供了一个exp,即eval(),其将command作为php代码来计算
于是我们先查看一下根目录
得到如下文件:
鉴于flag没有后缀,考虑其为文件夹的可能性,于是用cat命令查看flag/flag,得到题解
highlight_file() 函数对文件进行 PHP 语法高亮显示。语法通过使用 HTML 标签进行高亮。
**提示:**用于高亮的颜色可通过 php.ini 文件进行设置或者通过调用 ini_set() 函数进行设置。
**注释:**当使用该函数时,整个文件都将被显示,包括密码和其他敏感信息!
highlight_file(*filename,return*)
参数 | 描述 |
---|---|
filename | 必需。规定要显示的文件。 |
return | 可选。如果该参数设置为 TRUE,该函数将以字符串形式返回高亮显示的代码,而不是直接进行输出。默认是 FALSE。 |
eval()
函数把字符串按照 PHP 代码来计算。该字符串必须是合法的 PHP 代码,且必须以分号结尾。
**注释:**return 语句会立即终止对字符串的计算。
**提示:**该函数对于在数据库文本字段中供日后计算而进行的代码存储很有用。
eval(*phpcode*)
ls [-options] [target path]
选项 | 作用 |
---|---|
-a | 显示指定路径中的所有文件,包括隐藏文件 |
-l | 显示文件的详细信息,包括文件类型,权限,所属用户,所属用户组,文件大小,上一次修改时间等 |
-h | 文件大小以KBytes为单位显示 |
-S | 按照文件大小顺序显示,默认从大到小;若要从小到大,可使用-Sr |
上述各个选项可以叠加使用,从而能够显示出需要的信息。
第一位表示文件类型。d是目录文件,l是链接文件,-是普通文件,p是管道。
cat [-AbeEnstTuv] [--help] [--version] fileName
-n 或 --number:由 1 开始对所有输出的行数编号。
-b 或 --number-nonblank:和 -n 相似,只不过对于空白行不编号。
-s 或 --squeeze-blank:当遇到有连续两行以上的空白行,就代换为一行的空白行。
-v 或 --show-nonprinting:使用 ^ 和 M- 符号,除了 LFD 和 TAB 之外。
-E 或 --show-ends : 在每行结束处显示 $。
-T 或 --show-tabs: 将 TAB 字符显示为 ^I。
-A, --show-all:等价于 -vET。
**-e:**等价于"-vE"选项;
**-t:**等价于"-vT"选项;
ctf之路任重而道远,希望我能坚持下去吧