Custom HTTP Logging via Parsing Raw TCP

Last Update Article: 2024-06-23 12:56:13


HTTP Logging via TCP

Assalamualaikum warahmatullahi wabarakatuh, halo teman-teman pada artikel kali ini akan cukup singkat saja pembahasannya, karena ini akan menjadi bentuk dokumentasi pribadi saya yang sempat terlupa untuk beberapa saat. Jadi ceritanya ada sebuah grup di Whatsapp yang sudah lama tidak aktif dan tiba-tiba ada diskusi saya cukup panjang, saya sempat melontarkan chat singkat “Tumben ada diskusi”. Setelah scroll cukup panjang ke atas tiap-tiap diskusinya saya menemukan pertanyaan seperti ini.

Untitled

Jadi setelah membaca beberapa diskusi setelah chat itu berada, saya dapat menyimpulkan ada sebuah pertanyaan tentang cara memonitor sebuah request dari sebuah web yang sudah di-deploy tanpa merubah script yang ada dan juga tanpa menggunakan proxy apapun aka Nginx / HAproxy dan sejenisnya. Respon pribadi yang muncul dalam diri saya adalah “Hmm, apakah memang bisa?” tapi sejenak saya berifikir kembali apa itu Teminologi HTTP/s Request & Response yang hanya sebuah TCP format tertentu saja dan respon pribadi saya menjadi “Pasti bisa sih, ez”. Dari hasil diskusi yang ada mari kita mocking kejadian yang sedang dialami oleh penanya (saya tidak kenal beliau). Aplikasi web dibangun dengan golang/rust/nodejs atau bahasa apapun yang mempunyai HTTP server sendiri diserve langsung tanpa proxy dan dengan case menerima sebuah request.

HTTP Cycle TCP

Saya menyiapkan sebuah aplikasi Golang yang akan melakukan serving HTTP Server dan Endpoint dengan module net/http akan ada 2 endpoint yang ada, satu melakukan handling untuk GET parameter dan satu lagi akan melakukan handling JSON data dari POST method.

package main

import (
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

func main() {
    http.HandleFunc("/", helloWorldHandler)
    http.HandleFunc("/post", postHandler)

    fmt.Println("Server starting on port 8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

func helloWorldHandler(w http.ResponseWriter, r *http.Request) {
    if r.Method != http.MethodGet {
        http.Error(w, "Invalid request method", http.StatusMethodNotAllowed)
        return
    }
    w.WriteHeader(http.StatusOK)
    w.Write([]byte("Hello World"))
}

func postHandler(w http.ResponseWriter, r *http.Request) {
    if r.Method != http.MethodPost {
        http.Error(w, "Invalid request method", http.StatusMethodNotAllowed)
        return
    }

    body, err := io.ReadAll(r.Body)
    if err != nil {
        http.Error(w, "Unable to read request body", http.StatusBadRequest)
        return
    }
    defer r.Body.Close()

    var data map[string]interface{}
    if err := json.Unmarshal(body, &data); err != nil {
        http.Error(w, "Invalid JSON", http.StatusBadRequest)
        return
    }

    response := map[string]interface{}{
        "status": 200,
        "msg":    "ok",
    }

    responseData, err := json.Marshal(response)
    if err != nil {
        http.Error(w, "Unable to marshal response JSON", http.StatusInternalServerError)
        return
    }

    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusOK)
    w.Write(responseData)
}

Setelah dijalankan kita akan belajar secara singkat apa itu Three-Way Handshake yang mana menjadi sebuah proses yang digunakan oleh TCP untuk membentuk koneksi antara server dan client sebelum melakukan Terminologi HTTP/s. Dalam konsep Three-Way Handshake akan ada langkah-langkah sebagai berikut

  1. SYN (Synchronize)

    1. Client akan mengirimkan segmen SYN ke Server
    2. Segmen SYN ini akan berisi [seq] (Sequence Number) awal yang acak dari Client
     CLIENT --> [SYN, seq=(num)] --> SERVER
  2. SYN-ACK (Synchronize-Acknowledge)

    1. Server menerima SYN dari Client dan merespons dengan segmen SYN-ACK
    2. Segmen SYN-ACK berisi Sequence Number urut dari server dan mengembalikan ack sequence dari seq CLIENT yang ditambahkan satu
     CLIENT <-- [SYN, seq=0 (syn-seq), ACK, ack=seq-client+1] <-- SERVER
  3. ACK (Acknowledge)

    1. Client menerima segmen SYN-ACK dari server dan mengirimkan segmen ACK terakhir untuk konfirmasi koneksi
    2. Segmen ACK terkahir berisi seq-client + 1 dan syn-seq + 1

Untuk mengetahui Cycle TCP ini kita dapat menggunakan tools Wireshark dari Windows Client untuk melakukan Request ke Server 8080 milik Golang.

Untitled

Dari sini terlihat proses Three-Way Handshake telah dilakukan oleh Client dan Server, untuk detail prosesnya saya akan tuliskan sebagai berikut ini

  1. SYN Client

    1. Segmen 1 (Paket 12) - SYN dari Klien ke Server

       Seq=0, Ack=0, SYN
       192.168.110.107 -> 192.168.110.100 [SYN, Seq=0]
  2. SYN-ACK

    1. Segmen 2 (Paket 13) - SYN-ACK dari Server ke Klien

       Seq=0, Ack=1, SYN-ACK
       192.168.110.100 -> 192.168.110.107 [SYN, Seq=0, Ack=1]
  3. ACK

    1. Segmen 3 (Paket 15) - ACK dari Klien ke Server

       Seq=1, Ack=1, ACK
       192.168.110.107 -> 192.168.110.100 [ACK, Seq=1, Ack=1]

Setelah proses Three-Way Handshake telah dilakukan maka HTTP/s Terminilogi akan dilakukan antara Client dan Server berupa Request dan Response, hal ini bisa dicontohkan seperti berikut ini

  1. Request Raw

     POST /login.php HTTP/1.1
     Host: 192.168.110.100
     User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36
     Accept-Encoding: gzip, deflate
     Accept-Language: id-ID,id;q=0.9,en-US;q=0.8,en;q=0.7
    
     username=asd&password=asd

Client akan mengirimkan ada 3 part

  1. Method (GET|POST|PUT etc)

  2. Header (User-Agent, Host, etc)

  3. Body (JSON / Post Body)

  4. Response

      HTTP/1.1 200 OK
      Content-Type: text/html; charset=UTF-8
    
      {
          "status": 200,
          "msg": "ok"
      }

    Server akan mengirimkan 3 part juga

    1. HTTP status code (200, 500, 302, etc)
    2. Header (Cookie, Content-Type, etc)
    3. Body (JSON / Any)

Seperti yang saya coba tuliskan, di atas adalah sebuah proses Cycle untuk Three-Way Handshake untuk settle koneksi antara Client dan Server untuk kasus protokol HTTP ataupun protokol lainnya. Dari pengetahuan di atas sebenarnya tidak begitu berpengaruh dalam bagaimana proses Logging yang dapat dilakukan melalui Raw TCP ini, di atas hanyalah intermezo saja hehe.

Art of NGREP

Jika saya sudah bertele-tele menjelaskan tentang Three-Way Handshake TCP, kali ini akan berada di sisi server menggunakan NGREP (Network Grep), jika tadi melakukan inspeksi HTTP Request dengan menggunakan Wireshark yang berada di sisi Client, maka NGREP akan digunakan pada sisi Server yang menghosting aplikasi web-nya.

sudo ngrep -d any -W byline ".*" port 8080

Kita dapat melakukan inspeksi secara Real Time semua Request & Response yang ada di dalam server tertuju ke serve terkhusus ke port 8080. Fungsi dari -W byline ".*" agar lebih mempercantik output yang ada.

  1. Raw Output

    Untitled

  2. Splited Output

    Untitled

*PS: Di situ terlihat ada Cookies Khas PHP (PHPSESID) karena memang pada port 80 sedang listing riset dengan menggunakan PHP.

Dengan minimum CLI Command kita sudah mendapatkan sebuah Raw Request dan Response HTTP dari Client yang ada, tapi hasilnya masih sangat-sangat kotor sekali, cara terbaik untuk melakukan Remote Logging dari TCP Raw ini adalah dengan melakukan Pipingin lagi, kali ini saya menggunakan python3 untuk parsing.

import sys,re

request = ""
reqs = False

for data in sys.stdin:

    regex_method = r"GET|POST|HEAD|PUT|DELETE|OPTIONS|TRACE|CONNECT"

    if re.search(regex_method, data):
        reqs = True
        request = data
        continue

    if reqs:
        if len(data) < 3 and "#" in data:
            reqs = False
            print("Request: "+request+"\n")
            request = ""
        request += data
sudo ngrep -d any -W byline ".*" port 8080 | python3 ppp.py

Untitled

Inti dari script tersebut adalah dengan melakukan looping pada input STDIN via piping dari ngrep itu sendiri, setelahnya tiap-tiap Raw HTTP Request akan disimpan pada variable request yang mana dapat diolah lagi atau langsung dikirimkan ke tempat-tempat Log saver yang diinginkan untuk mengolah-nya yang penting sekarang variable request sudah berisi log “bersih” dari client.

Penutup

Terima kasih telah membaca teman-teman, ngrep ini adalah tools yang menemani saya dalam menjadi SOC L1-L3 pada karir saya sebelumnya, dan juga dalam kompetisi Attack & Defense sangat saya andalkan untuk mengintip payload-payload milik team lain yang sedang menyerang xixi. Mohon maaf jika ada kesalahan dalam penjelasan yang saya tuliskan saya sangat siap untuk merevisi dan berdiskusi! <3