09/11/25
SROP,StackPivotiFSOP
Reptes Pwn | CyCTF 2025
Thanks for sharing!
بِسْمِ اللَّهِ الرَّحْمَنِ الرَّحِيمِ

I know your browser history
Fa temps que no ens veiem, gent! He tornat amb alguns productes frescos dels recents CyCTF Quals. Vaig poder esborrar pwn alhamdulillah, així que cobriré tots els reptes d'aquest escrit. Tot estarà en detalls amb fonts per a tot! Comencem!
Tots els reptes es poden trobar aquí.
pwn1 (481 pts)
Aquest va ser un repte clàssic FSOP (File Stream Oriented Programming). Busquem en el codi font per veure què passa.
Anàlisi del codi font
El codi descompilat mostra un programa senzill basat en menús.
Aquí teniu un desglossament de les parts interessants:
load_flag(): aquesta funció llegeix la bandera deflag.txta un buffer global. L'adreça d'aquest buffer és0x404300, que necessitarem més endavant. (Podeu obtenir-lo des de gdb o simplement fent-hi doble clic al descompilador.)fh = fopen("/dev/null", "w"): el programa obre/dev/nulli emmagatzema el punterFILEen una variable globalfh. S'ha assignat una estructuraFILEper gestionar aquest flux.- La vulnerabilitat: hi ha una opció de menú oculta,
1337(0x539). Quan es tria, el programa executaread(0, fh, 307). Aquest és l'error! Llegeix 307 bytes de la nostra entrada directament a la ubicació de memòria apuntada perfh. Com quefhapunta a una estructuraFILEal munt, podem sobreescriure el seu contingut completament.
Aquesta és una configuració de llibre de text per a un atac FSOP. En controlar l'estructura
FILE, podem manipular com es comporten les funcions d'E/S com fwrite i fflush.Estructura del fitxer?
Aleshores... què dimonis és això?
L'estructura
FILE és una representació interna que utilitza la biblioteca estàndard C (libc) per gestionar els fluxos de fitxers. Conté diversos camps que fan un seguiment de l'estat del flux, inclosos els punters de memòria intermèdia, els indicadors i els punters de funció per a les operacions d'E/S.L'estructura té aquest aspecte (estructura simplificada i completa aquí):
Quan anomenem funcions com
fwrite o fflush, es basen en la informació de l'estructura FILE per determinar com gestionar les dades.I això és exactament el que farem, sobreescriurem l'estructura
FILE per fer que fwrite llegeixi des de la ubicació de memòria de la bandera i l'imprimirem. I podeu endevinar com es diu aquesta tècnica? sí, FSOP!Cobriré només els coneixements necessaris per resoldre aquest repte, per obtenir més informació sobre l'estructura FILE, podeu cercar
Què és FSOP?
FSOP, o programació orientada a fluxos de fitxers, és una tècnica que us permet corrompre l'estructura
FILE.Si sobreescriu una estructura
FILE, podem obtenir control sobre el flux d'execució del programa. Per exemple, quan es crida fflush(fh) o fwrite(..., fh), libc utilitzarà els punters de funció dins de la nostra estructura danyada, la qual cosa ens permetrà redirigir l'execució a codi arbitrari o, en aquest cas, desencadenar comportaments específics beneficiosos per a nosaltres.Un recurs per entendre l'explotació de l'estructura FILE és pwn college, niftic.ca o qualsevol altre recurs FSOP.
El pla d'explotació
El nostre objectiu és llegir la bandera de la memòria a l'adreça
0x404300. Aquí teniu el pla pas a pas:- Trieu l'opció de menú amagada
1337. - Envieu una càrrega útil especialment dissenyada que sobreescriurà l'estructura
FILEa la memòria. - Aquesta nova estructura
FILEfalsa es configurarà per fer que la propera trucadafwriteens filtri la bandera.
Aleshores, com fem que
fwrite, una funció per escriure, ens llegeixi dades arbitràries?Penseu en com funciona internament
fwrite. Llegeix dades d'un buffer i les escriu a una destinació. La ubicació i la mida d'aquest buffer s'emmagatzemen dins de la pròpia estructura FILE, utilitzant punters com _IO_write_base i _IO_write_ptr.El nostre atac és sobreescriure l'estructura
FILE i canviar aquests punters. Establirem _IO_write_base perquè apunti a l'inici de la ubicació de memòria de la bandera (0x404300), _IO_write_ptr a _IO_write_base + length i fileno a 1 (stdot_6__).filenoés el número del descriptor del fitxer,1correspon a la sortida estàndard (stdout). En configurar-ho, diem afwriteque escrigui a la consola.
També hi ha una peculiaritat en què hem d'establir
_IO_read_end a _IO_write_base, no sé per què, però té a veure amb la implementació de fwrite, es va esmentar a pwn.college.
Per descomptat, la funció d'escriptura de pwntools gestiona tot això!

Quan el programa crida de nou a
fwrite, mirarà la nostra estructura maliciosa FILE i pensarà que la memòria del senyalador és el seu buffer de dades. A continuació, procedirà a "escriure" el contingut d'aquest buffer (la bandera) a la seva destinació, que en el nostre cas és una sortida estàndard. Hem convertit amb èxit una funció d'escriptura en un gadget de lectura de memòria arbitrari!Podeu escriure l'estructura
FILE vosaltres mateixos, però pwntools ho facilita amb la seva utilitat pwnlib.filepointer.FileStructure. Simplement podem dir-li de quina adreça volem llegir i ens generarà tota la càrrega útil.L'explotació
L'explotació final és sorprenentment curta, gràcies al poder de
pwntools.pay = fp.write(FLAG_ADDR, 0x100): aquest és el nucli de l'explotació. Genera una cadena de bytes que representa una estructuraFILE. Aquesta estructura falsa està configurada de manera que qualsevol operació d'escriptura en ella llegeixi realment0x100bytes deFLAG_ADDRi els escrigui a la sortida del flux (que ésstdoutper defecte).- La
read(0, fh, 307)del programa sobreescriu l'estructuraFILEreal amb la nostra falsa. - Les trucades
fwriteifflushposteriors operen a la nostra estructura maliciosa, llegeixen la bandera de la memòria i la imprimeixen.
Quin passeig! Tot i que aquest va ser el primer repte pwn, va ser el que va tenir menys solucions. Ara anem a la següent!
pwn2 (460 pts)
Aquest següent repte va ser divertit i va implicar un desbordament de memòria intermèdia que es va convertir en un atac de programació orientada a Sigreturn (SROP) per obtenir un shell.
Anàlisi del codi font
Vegem el codi descompilat.
Podeu detectar immediatament el bof a la funció
check_password. Assigna un buffer de 32 bytes (local_28) a la pila, però després utilitza read per escriure-hi 0x200 (512) bytes.El pla d'explotació
Has de saber què és el SROP i el pivotament de la pila abans de continuar, alguns bons recursos són: ir0nstone i pwn.college
En un repte SROP típic, s'utilitzarà
execv amb /bin/sh, però primer necessitem una adreça que indiqui /bin/sh, això és el que no tenim aquí. Tot i que el nom d'usuari podria contenir la cadena, no hi ha cap fuga de pila per descobrir la seva adreça exacta. Així doncs, el meu pla era utilitzar read per posar la cadena /bin/sh a .bss i després fer un altre SROP per a execv.- Gol
obtenir un shell abusant del desbordament de la pila
check_password per realitzar dos fotogrames SROP encadenats:- El primer marc SROP
read(0, .bss, 0x200)per escriure/bin/shi un segon marc SROP a.bssi establiràrspa aquesta àrea. - El segon marc SROP fa
execve("/bin/sh", 0, 0).
Per què SROP aquí: Com que no hi ha cap gadget per configurar
rdi, SROP ens permet configurar tots els registres des d'un marc sigcontext dissenyat i trucar a syscall, només un gadget per configurar rax i un Cal el gadget syscall/ret.Per alguna raó no vaig poder fer que el primer SROP tornés directament al segon, així que vaig girar la pila.
- Flux d'alt nivell
- Desbordament de la memòria intermèdia
passwordi el retorn de sobreescriure per activar un petit ROP que:- estableix
raxen0xF(valor d'activació sigreturn), crida al gadgetsyscallper invocarsigreturn.
- estableix
- El primer fotograma de sigreturn (permet que l'anomenem fotograma A) estableix registres per trucar a
read(0, bss, 0x200)i, de manera crucial, estableixrspabss + 0x100(pivot de pila).rip= gadgetsyscall, de manera que s'executaread. - Envieu la càrrega útil per a
read:/bin/sh\x00encoixinat fins abss + 0x100, seguit d'un segon fotograma de sigreturn (fotograma B). - Quan torna
read, l'execució continua alrsppivotat a.bss, ara apuntant al fotograma B; Es torna a invocarsigreturn(mitjançant el gadgetsyscall) per omplir els registres deexecve. - El marc B estableix
rax=59,rdi=bss(punter a/bin/sh),rsi=0,rdx=0,rip=syscall.syscallexecutaexecve("/bin/sh", 0, 0)-> shell.
Tots els números de syscall són per a x86_64 Linux es poden trobar aquí
L'explotació
Primer anem a triar un espai lliure d'escriptura a la memòria

Tenim
0x4040b0.- Truqueu a llegir (...) i pivotar la pila
Ara volem
read(0, bss_addr, 0x200) i rsp = bss_addr + 0x100:- Disseny de la segona etapa (el que enviem a llegir())
Les dades que enviem després del fotograma A (mitjançant el
read) han de contenir, per ordre:- la cadena
b"/bin/sh\x00"(ubicada abss_addr), - farciment fins a
bss_addr + 0x100, - gadgets per tornar a activar
sigreturn(pop rax; 0xf+syscall), - quadre B (
SigreturnFrame).
Concretament, en el vostre exploit, creeu
second_stage com:- Marc B: execve("/bin/sh", 0, 0)
El marc B estableix registres per a
execve (syscall 59) i apunta rdi a bss_addr on s'emmagatzema /bin/sh:L'explotació final és així:
I així, tenim una closca!
pwn3 (464 pts)
El repte final de pwn va ser un bon repte que va implicar un desbordament de memòria intermèdia per manipular els arguments d'una trucada
mmap, cosa que ens va permetre executar el codi de comandament.Anàlisi del codi font
Podeu detectar immediatament el bof a
fgets(buf, 160, stdin), on buf només fa 128 bytes. Hi ha un enter mmap_prot just després d'ell a la pila, que s'utilitza com a tercer argument de mmap.Què és mmap()?
mmap és una trucada al sistema que també es pot utilitzar per assignar regions de memòria amb permisos específics (llegir, escriure, executar). La signatura de la funció és:Els arguments importants que hem de conèixer per a aquest repte són:
addr: Adreça d'inici desitjada per al mapeig.length: Mida del mapeig en bytes.prot: indicadors de protecció de memòria (p. ex.,PROT_READ,PROT_WRITE,PROT_EXEC).
Anàlisi del codi font Cont.
mmap s'utilitza per assignar una regió de memòria a una adreça fixa 0x500000 amb mida 0x40000 i permisos definits per mmap_prot. Inicialment, mmap_prot s'estableix en 3, el que significa que la regió serà llegible i escrivible, però no executable.Tanmateix, com que
mmap_prot es troba a la pila just després del nostre buf, el podem sobreescriure amb el nostre desbordament de memòria intermèdia!El pla d'explotació
El pla és introduir el codi shell en una regió de memòria executable i després saltar-hi.
- Sobreescriure
mmap_prot: utilitzarem el desbordament de memòria intermèdia per canviar el valor demmap_protde3(RW-) a7, que és3(RW-) a7, (EN_MD__)PROT_READ | PROT_WRITE | PROT_EXEC. Això farà que la regió de memòria assignada permmapsigui executable. - Colocar Shellcode: el programa copia la nostra entrada de
bufa la regió recentment mapejada ambmemcpy. Això significa que el nostre shellcode, situat al principi de la nostra entrada, es copiarà a la regió de memòria executable. - Sobreescriu l'adreça de retorn: continuarem el desbordament més enllà de
mmap_protper sobreescriure l'adreça de retorn desada amb0x500000, l'adreça del nostre codi d'intèrpret d'ordres ara executable.
L'explotació
L'execució de l'explotació envia la càrrega útil dissenyada amb cura. El programa es desborda, mapeja una regió de memòria executable, hi copia el nostre codi d'intèrpret d'ordres i després salta directament al codi d'intèrpret d'ordres en tornar.
Això és tot per avui! Espero que us hagi agradat aquest escrit tant com jo he gaudit resolent els reptes. Pots Dox'm a X/Twitter des d'aquí. Ens veiem la propera vegada! 🍄🍄
Etiquetes:

