Semgrep + CSRF Detection in WordPress Plugs

Imhunterand
6 min readNov 3, 2023

Introduction

Sedikit perkenalan, bulan ini, saya menemukan semgrep. Semgrep adalah alat analisis statis yang kuat. Semgrep mendukung banyak bahasa, termasuk php. Semgrep juga lebih mudah dipelajari dibandingkan dengan codeql. Anda bisa membaca perbandingan yang bagus antara keduanya di blog spaceracoon.

Semgrep

Introduction to Semgrep

Semgrep adalah alat analisis kode statis, di mana kita dapat menulis aturan kita sendiri. “Aturan” ini adalah pola yang kita inginkan untuk ditemukan oleh semgrep. Ambil aturan ini sebagai contoh

Kita mencocokkan fungsi tersebut dengan menggunakan aturan ini. Dalam semgrep tiga titik (…) berarti mencocokkan apa saja, dan semua kata kunci yang dimulai dengan $ dan hanya memiliki huruf besar disebut metavariabel, ini seperti variabel untuk semgrep. Untuk mempelajari lebih lanjut tentang semgrep, read the documentation.

Join Mode

Pada saat tulisan ini dibuat, hanya beberapa bahasa di semgrep yang mengizinkan analisis lintas berkas. Namun, semgrep memiliki fitur eksperimental yang disebut “join mode”. Join mode memungkinkan kita untuk menggunakan beberapa aturan, dan melakukan perbandingan antara metavariabel dari aturan-aturan tersebut. Kecocokan antara aturan-aturan ini dapat berasal dari file yang berbeda. Mari kita tunjukkan sebuah contoh sederhana

Untuk contoh ini, kita akan mencoba menemukan xss yang direfleksikan secara sederhana di django. Saya membuat dua file, sebuah file python yang memanggil untuk melakukan render, dan sebuah file html, sebagai template yang akan di-render

Dan inilah aturan semgrep yang saya buat untuk itu :

rules:
- id: demo
mode: join
join:
rules:
- id: call-to-render
languages: [python]
pattern: "render(request, $TEMPLATE, {..., '$PARAMETER': ..., ...})"
- id: variable-marked-with-safe
languages: [generic]
pattern: "{{ $VARIABLE | safe }}"
on:
- 'call-to-render.$PARAMETER == variable-marked-with-safe.$VARIABLE'
- 'call-to-render.$TEMPLATE > variable-marked-with-safe.path'
message: "TEST"
severity: INFO

Mari kita uraikan, aturan pertama, “call-to-render” mencocokkan semua panggilan render pada berkas python. Ini memiliki dua metavariabel, $TEMPLATE yang merupakan file template html, dan file$PARAMETER yang merupakan nama parameter yang akan diteruskan pada template

Aturan kedua “variable-marked-with-safe”,mencocokkan pola {{ $VARIABLE | safe }} . Ini memiliki metavariabel yang disebut$VARIABLE yang merupakan nama variabel yang dirender sebagai aman.

Pada “on” bagian, Di sinilah keajaiban dari aturan penggabungan terjadi. Di sinilah kita meletakkan perbandingan yang ingin kita lakukan di antara aturan-aturannya. Baris pertama mengecek, apakah aturan $PARAMETER variabel dari “call-to-render” sama dengan aturan $VARIABLE parameter dari variable-marked-with-safe . Baris kedua, menggunakan tombol “<” yang cocok jika operator $TEMPLATE variabel dari “call-to-render” adalah substring dari jalur file dari kecocokan bertanda variabel-dengan-aman.

Menjalankan ini, memberikan hasil yang kami harapkan. Pelajari lebih lanjut tentang aturan penggabungan di documentation

Recursive Join

Semgrep juga memiliki sesuatu yang disebut gabungan rekursif. Sulit untuk dijelaskan, tetapi pada dasarnya, ini secara rekursif mencocokkan sebuah aturan dan menghasilkan tabel untuk aturan tersebut. Untuk menggunakannya, kita menggunakan operator penggabungan aturan --> . contoh dari semgrep

Jika kita menggunakan aturan penggabungan rekursif di sini, maka akan menghasilkan tabel seperti ini

Dengan menggunakan ini, kita dapat memeriksa apakah sebuah fungsi, entah bagaimana, akan melakukan pemanggilan ke fungsi lain. Mari kita lihat contoh sederhana, Ini adalah file python

def function1():
dangerous()
def demo(request):
function1()

Dan ini adalah aturan semgrep

rules:
- id: demo
mode: join
join:
rules:
- id: callgraph
languages: [python]
patterns:
- pattern: $CALLEE(...)
- pattern-inside: |
def $CALLER(...):
...
- id: dangerous-function
languages: [python]
patterns:
- pattern: "$DANGEROUSFUNC(...)"
- metavariable-regex:
metavariable: $DANGEROUSFUNC
regex: dangerous
on:
- 'callgraph.$CALLER --> callgraph.$CALLEE'
- 'callgraph.$CALLEE == dangerous-function.$DANGEROUSFUNC'
message: "TEST"
severity: INFO

Singkatnya, apa yang dilakukan oleh aturan ini adalah memeriksa apakah sebuah fungsi melakukan pemanggilan ke fungsi berbahaya. Seperti inilah tampilan callgraph-nya

Kita dapat melihat bahwa demo function memiliki panggilan untukdangerous function yang berarti juga dicocokkan dengan aturan ini. Anda dapat membaca lebih lanjut tentang gabungan rekursif di bagian documentation.

Patching Semgrep

Aturan penggabungan memang bagus tetapi kita memiliki masalah. Penggabungan rekursif bagus untuk menemukan fungsi mana yang melakukan pemanggilan ke fungsi lain, tetapi csrf di sisi lain, ada jika fungsi tersebut tidak melakukan pemanggilan ke fungsi proteksi. Saat ini tidak ada fungsionalitas untuk semgrep untuk mengecek apakah suatu fungsi tertentu tidak melakukan pemanggilan ke fungsi lain, jadi saya membuat beberapa perubahan bodoh pada kode untuk membuatnya bekerja seperti yang saya butuhkan.

Saya tidak akan menjelaskannya karena tidak dilakukan dengan baik, tetapi dengan membacanya Anda akan mendapatkan gambaran. Namun secara ringkas, saya membuat operator lain, khusus untuk callgraphs saja, yaitu operator !!, yang mengecek apakah pemanggil tidak akan melakukan panggilan ke fungsi tertentu.

Rule for finding csrf

Dengan itu, saya berakhir dengan aturan ini.

rules:
- id: wp-wpajax-csrf
mode: join
join:
rules:
- id: wpajax-actions
languages: [php]
patterns:
- pattern-either:
- pattern: add_action('$ACTION', [$UNIMPORTANT, '$HOOKFUNC']); ## SOME DEVS DO THIS. THE FIRST ARGS ARE THE CLASS
- pattern: add_action('$ACTION', '$HOOKFUNC');
- metavariable-regex:
metavariable: $ACTION
regex: (wp_ajax_).*
- id: callgraph
languages: [php]
patterns:
- pattern: $CALLEE(...)
- pattern-inside: |
function $CALLER(...){
...
}
- id: csrf-protection
languages: [php]
patterns:
- pattern: $CSRFPROTECTFUNC(...) # FIND CALLS TO CSRF PROTECTIONS
- metavariable-regex:
metavariable: $CSRFPROTECTFUNC
regex: (check_ajax_referer|check_admin_referer|wp_verify_nonce)
on:
#- 'callgraph.path == wpajax-actions.path' # Experimental. Remove this line for more result
- 'callgraph.$CALLEE !! csrf-protection.$CSRFPROTECTFUNC' #Use !! to check if a function somehow will not reach a certain call. the first paratmeter should always be the callgraph $CALLEE the second is the function we want to check if it doesnt reach
#Good for finding csrf ^
- 'callgraph.$CALLER --> callgraph.$CALLEE'
- 'callgraph.$CALLER == wpajax-actions.$HOOKFUNC'
message: "This ajax action doest call csrf protection functions"
severity: INFO

Result

Semua bug yang saya temukan dilaporkan melalui Patchstack. Yang menyenangkan dari PatchStack adalah mereka menangani pengungkapan bug ke vendor. Mereka juga memiliki papan peringkat bulanan, di mana Anda bisa menerima hadiah uang tergantung pada poin Anda.

Saya menjalankan aturan semgrep di semua proyek wordpress dengan setidaknya 10 ribu instalasi. Saya menggunakan notifikasi projectdiscovery untuk menerima pemberitahuan di server discord saya jika menemukan kecocokan.

Ini adalah hasil dari proyek kecil ini

Scanned Plugins: 2524
Plugins with findings: 510
Total Reports: 55
Accepted: 43
Rejected: 12
False Positive: 455

Bug yang ditemukan ini bervariasi tingkat keparahannya, mulai dari menonaktifkan fungsi plugin tertentu hingga RCE!!!. Seperti yang Anda lihat, ada banyak sekali false positive sehingga saya harus menghabiskan banyak waktu untuk memeriksa satu per satu. sekian dari saya terimakasih dan selamat memahami materi-materi tersebut.

Saya merasa banyak orang di komunitas infosec yang tidur di semgrep. Codeql lebih populer tetapi semgrep bagi saya, sama bagusnya, bahkan lebih baik. Terima kasih semgrep untuk alat yang luar biasa dan terima kasih patchstack karena telah bekerja sama dengan saya dalam laporan saya. Terima kasih sudah membaca.

Twitter saya yang sebelumnya telah dinonaktifkan, jadi jika Anda mau, silakan ikuti saya di akun instagram saya yang lama : @youryreborn

--

--

Imhunterand

father, spare time hacker with a background in software development and penetration tester experience. H1: @private