ROP/ret2lib/zwał to nie tyle metoda "ataku" (co jest dość wysokopoziomowym określeniem na cały proces), co exploitacji. Żeby w ogóle dojść w procesie exploitacji do ROP trzeba najpierw mieć dwie rzeczy:
- Możliwość wykonania kodu spod wskazanego adresu (tj. kontrolowane RIP/EIP/IP/PC, słynne 41414141).
- Kontrolowany stos (konkretniej, kontrolowana zawartość stosu).
Spełnienie tych warunków albo dostaje się gratis z uwagi na rodzaj błędu, który się exploituje (jak np. stack-based buffer overflow), albo trzeba do tego doprowadzić we wcześniejszych krokach procesu exploitacji (np. w błędach klasy use-after-free możemy często dostać tzw write-what-where - czyli możliwość zapisania kontrolowanej wartości w kontrolowane miejsce w pamięci, a z tego z kolei można przejść do wykonania kodu z ograniczeniem do jednego gadżetu, z tego do stack pivot - co nam daje kontrolowany stos przez de fact zmianę regionu który nazywany stosem, i dopiero wtedy docieramy do ROP).
Ale ostatecznie docieramy do momentu kiedy możemy stosować ROP, jak i do odpowiedzi na pierwsze pytanie:
w jaki sposób instrukcje, jakie są pokazane na rysunku 2, mogą być zinterpretowane od innego adresu zanim wykorzystano tak powstałą instrukcję “ret”
Zgodnie z pierwszym wymaganiem ROP, musimy już w tym momencie móc powiedzieć który kod ma się zacząć wykonywać, tj. w jakiś sposób wymusić skok we wskazane miejsce. Co za tym idzie, możemy po prostu wskazać miejsce w środku instrukcji. To nie jest coś co ROP daje, to jest coś co jest wstępnym wymaganiem ROP.
po co jeszcze kolejna instrukcja “ret”?
ROP polega na "chainowaniu" (łączeniu w łańcuch) wielu gadżetów (kawałków kodu zakończonych instrukcją ret lub ekwiwalentem), tak, żeby zrobić coś więcej niż wykonać te kilka instrukcji przed ret. Jak się ma dużo gadżetów, to można sobie je tak połączyć, żeby np. zaalokować pamięć z prawami RWX, doczytać z socketu sieciowego dodatkowy shellcode tam, i go wykonać (bez restrykcji, które ma ROP).
Więc to co oni tam pokazują, to po prostu kilka różnych gadżetów, które najczęściej kończą się na C3 (ret).
W praktyce ROP to po prostu podanie wielu adresów powrotu na stosie, które są następnie potem zczytywane przez kolejne rety z kolejnych gadżetów w łańcuchu (gdzie łańcuch jest definiowany właśnie przez te adresy na stosie). Te adresy jeszcze są przeplatane argumentami / dopełnianiami btw.
100 lat temu opisałem to trochę bardziej na blogu, ale chyba używałem wtedy trochę innej terminologii jeszcze niż obecnie przyjęty "gadżet". Anyway: https://gynvael.coldwind.pl/?id=144