6. Функция php_execute_script всегда вызывает zend_execute_scripts, поэтому в стеке всегда будет адрес возврата обратно в php_execute_script. Находим адрес символа php_execute_script, читаем код функции, ищем, где в ней вызывается zend_execute_scripts@plt.
Важно! Новые версии компиляторов, например GCC 9, входящий в Ubuntu 20.04, помещают код для вызова импортируемых через @plt функций в секцию “.plt.sec”. Парсим секцию “.plt.sec”, находим в секции запись соответствующую функции zend_execute_scripts. Подробнее про секцию “.plt.sec” можно почитать тут.
7. Ищем посчитанный адрес возврата в стеке. Если имеем дело с потоко-безопасным PHP, то любой поток может обработать запрос от клиента, причем заранее неизвестно какой именно. Поэтому сканируем стеки всех потоков. Размер стека потока в pthreads по умолчанию 8 Мб. Ищем регионы такого размера в /proc/self/maps, сканируем найденные регионы памяти в обратном направлении в поисках адреса возврата. Найдя в стеке адрес возврата, записываем туда ROP-цепочку.