Pages

2/06/2011

WebGoat : HTTP Splitting

เพราะว่าทำเองไม่เป็นแหละ เลยไปเปิดเฉลยแล้วมาลอง ฮ่าๆ
ลองแล้วสำเร็จ เลยต้องมาเขียนโน๊ตไว้เตือนตัวเองซะหน่อย

HTTP Splitting

เรื่องของเรื่องก็คือ HTTP เนี่ย เป็น protocol ที่ใช้ส่งข้อมูล โดยใช้ระบบตัวหนังสือส่งเป็นหลัก ทั้งคำสั่งและข้อมูล
และใช้เครื่องหมายขึ้นบรรทัดใหม่เป็นตัวแบ่งคำสั่งต่างๆ

ดังนั้น ถ้าเราสามารถส่งข้อมูลไปที่เวปserver  แล้วเมื่อwebserverส่งข้อมูลนั้นกลับมา คำสั่งที่แทรกอยู่บนนั้นก็จะหลอกเครื่องเป้าหมายให้ทำงานผิดพลาดได้หรือไม่

โจทย์อันนี้เลยเริ่มมาจากว่า ให้เรากรอกข้อมูลซึ่งเป็นภาษาลงไป เพื่อที่จะ redirect user ไปหาหน้าเวปที่ตรงกับภาษานั้น
ยกตัวอย่างเช่น ถ้าเรากรอก en (ภาษาอังกฤษ) ลงไป
หน้า redirect จะส่งผุ้ใช้ไปที่


ก็คือเอาคำว่า en ไปต่อท้าย redirect URL อย่างที่เห็น

มาเริ่มต้นเนื้อหากัน

Stage 1
ด่านแรกของโจทย์นี้คือ
ให้ทดลองส่งคำสั่งพวกนี้ไป เพื่อจำลองว่าเราสามารถแทรกคำสั่งHTTPลงไปในinputได้
ซึ่งในช่อง input เราจะใส่ไอ้นี่ไป
en
Content-Length: 0

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 30
<html>Hacked by anidear</html>

ชุดแรกหมายถึง
en คือเป็นinputปกติ คือเราจะตอบคำถามที่ทาง web application หน้านั้นถามเรา
Content-Length: 0 คือไม่มีข้อความอะไรต่อจากตรงนี้แล้วในrequest header
เพื่อที่จะบอกว่าหมดrequest headerแล้วด้วย
แต่เราดันเว้นว่างบรรทัดนึง แล้วแทรกข้อความresponseต่อเลย
โดยข้อความresponseมีเนื้อหาว่า
HTTP/1.1 200 OK :บอกว่าข้อความresponseนี้ใช้การส่งแบบHTTP version 1.1 และหน้าที่คุณร้องขอมีอยู่จริงและเรากำลังจะส่งข้อมูลให้
Content-Type: text/html :ข้อมูลต่อไปนี้เป็นtext/html
Content-Length: 30 :ข้อความเนื้อหาต่อไปนี้ยาว30ตัวอักษร
แล้วก็ตามด้วยข้อความที่เราอยากจะโชว์ขึ้นที่หน้า user (ซึ่งมีความยาว30ตัวอักษร อยากได้ยาวกว่านี้ก็แก้เลข30เอาเอง)

ปัญหาก็คือว่า การส่งคำสั่งพวกนี้ซึ่งมีเครื่องหมายขึ้นบรรทัดใหม่อยู่ มันไม่สามารถส่งเข้าไปในURLได้
ดังนั้นเราจึงต้องทำการแปลงให้มันอยู่ในรูปแบบของURIซะก่อน
ซึ่งจะใช้อะไรก็ได้ ตั้งแต่ javascript(คำสั่ง encodeURI('string')) หรือว่าเครื่องมืออื่นๆ
ในที่นี้(จากเฉลย) เขาแนะนำให้ใช้จากเวปนี้ http://yehg.net/encoding/ ซึ่งรวมวิธีการencodingไว้หลายแบบด้วย
โดยเมื่อกรอกข้อความที่ต้องการencodeลงไปแล้ว ให้กดปุ่ม encodeURIComponent ก็จะได้ผลออกมา

** สำหรับผู้ใช้ที่เป็นwindows เนื่องจากระบบของwindowsจะมองการขึ้นบรรทัดใหม่เป็น \r\n
ดังนั้นจึงจะต้องแปลงตัวอักษรขึ้นบรรทัดใหม่เป็น %0D%0A ด้วย
แทนที่จะเป็นแค่ \n หรือ %0A อย่างเดียวของบนLinux
ตรงนี้จะเพิ่มเองด้วยมือก็ได้ หรือถ้าใช้หน้านั้นให้เข้า Text FX, Convert, from %0A to %0D%0A

แปลงเป็น URI format แล้วจะได้เป็น
en%0AContent-Length%3A%200%0A%0AHTTP%2F1.1%20200%20OK%0AContent-Type%3A%20text%2Fhtml%0AContent-Length%3A%2030%0A%3Chtml%3EHacked%20by%20anidear%3C%2Fhtml%3E


ก็จะทำให้ได้ผลลัพธ์แบบนี้

ถึงตรงนี้จะเห็นว่าทุกอย่างมันรวมกันไปอยู่บรรทัดเดียว
แต่ว่าเวลาbrowserตีความ ก็จะแปลงข้อความตรงนี้ออกมาตีความ
แล้วก็จะเห็นว่าหน้านี้ไม่ต้องredirectแล้ว เพราะมีข้อความมาเรียบร้อยแล้วอยู่บ้างในตามที่เราได้ใส่เอาไว้ก่อนหน้า

Stage 2

ด่านสองของโจทย์นี้คือการทำ Cache Poisoning
นั่นคือว่า การโจมตีแบบนี้จะไม่ได้ผลอะไรเท่าไหร่ เพราะว่าเราต้องกรอกเองถึงจะได้เห็นเอง
หรือไม่ก็ต้องส่งURLเป็นparameterแบบยาวๆนั่น ก็จะลำบาก เพราะมันง่ายต่อผู้ใช้ในการสังเกตุURLยาวๆนั่น
แต่ cache poisoning เป็นการทำไว้ทีเดียวเลย

โดยอาศัยหลักการที่ว่า Web Cache (หรือ WebProxy) จะเช็คดูในresponse HTTP message ว่าหน้าเวปเวปนี้ถูกแก้ไขครั้งล่าสุดเมื่อไหร่
cache ก็จะเช็คข้อมูลของตัวเองว่าตัวเองมีข้อมูลที่เก่าหรือว่าใหม่แล้ว ถ้าcacheมีข้อมูลเก่าแล้ว (คือLast Modified เป็นวันที่ในอดีต) cache ก็จะเอาข้อมูลใหม่ทับลงไป ในทางตรงกันข้ามถ้าเกิดว่าข้อมูลของ cacheยังใหม่อยู่ cacheก็จะไม่มีการเรียกไปหน้าเวปใหม่ แต่จะใช้ข้อมูลที่ถูกเก็บเอาไว้ ทั้งนี้เพื่อที่จะประหยัดbandwidthการส่งข้อมูลลงไป เพราะไม่ต้องrequestไปหาserverใหม่ทุกครั้งที่ต้องการหน้านั้น(ที่ยังไม่ได้มีการแก้ไข)

ดังนั้น ถ้าเราเขียน Last Modified เป็นวันที่ในอนาคตล่ะ?
cacheก็จะมองว่า ข้อมูลนี้มันไม่เก่าซักทีน่ะสิ ก็จะทำให้ส่งข้อมูลเดิมให้กับผู้ใช้ตลอด
นี่แหละที่จะทำให้การattackด้วย HTTP Splitting นี่ส่งผลได้รุนแรงที่สุด


ดังนั้นเราก็จะเพิ่มบรรทัด Last-Modified: Mon, 1 Jan 2100 11:11:11 GMT
เอาไปศตวรรษหน้าไปเลย ฮ่าๆๆ

requestที่ต้องส่งไปก็จะเป็น
en
Content-Length: 0

HTTP/1.1 200 OK
Content-Type: text/html
Last-Modified: Mon, 1 Jan 2100 11:11:11 GMT
Content-Length: 30
<html>Hacked by anidear</html>

เมื่อแปลงเป็น URI แล้ว จะได้เป็น
en%0AContent-Length%3A%200%0A%0AHTTP%2F1.1%20200%20OK%0AContent-Type%3A%20text%2Fhtml%0ALast-Modified%3A%20Mon%2C%201%20Jan%202100%2011%3A11%3A11%20GMT%0AContent-Length%3A%2030%0A%3Chtml%3EHacked%20by%20anidear%3C%2Fhtml%3E


และแล้วก็จะได้ผลลัพธ์เป็นแบบนี้

และแล้วก็ทำให้ผ่านโจทย์นี้ไปได้ซักที เฮ้อ..

ขอได้รับความขอบคุณจาก
yehg.net ผู้ทำเฉลยดีๆให้ดู
OWASP ผู้สร้างwebgoat
และ Google Chrome สำหรับการดักจับHTTP packets

No comments:

Post a Comment