diff --git a/.gitignore b/.gitignore index d58c97f..447b2d7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,7 @@ +references_for_redisign src/main/resources/static/* +!src/main/resources/static/fake +!src/main/resources/static/fake/** *.pcap data diff --git a/README.md b/README.md index 5b92747..cf72393 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@
-# Packmate +# 0xb00b5 team Packmate
### [[EN](README_EN.md) | RU] -Утилита перехвата и анализа трафика для CTF. +Утилита перехвата и анализа трафика для CTF, переосмысленная в пиксельном неоне. #### Фичи: * Поддерживает перехват живого трафика и обработку pcap файлов @@ -23,14 +23,18 @@ * Разархивирует GZIP в HTTP на лету * Разархивирует сжатые WebSockets * Расшифровывает TLS на RSA при наличии приватного ключа +* Обманка для входа `admin:admin` с режимами `fun` и `fake_packets`, чтобы любопытные так и не добрались до настоящих пакетов ![Скриншот главного окна](screenshots/Screenshot.png) +### Обманка admin:admin +Для входа с кредами `admin:admin` добавлена обманка (включена по умолчанию). Управляется через переменные `PACKMATE_FAKE_ADMIN_ENABLED` и `PACKMATE_FAKE_ADMIN_MODE` (`fun` или `fake_packets`) и не дает добраться до настоящего интерфейса. + ## Быстрый запуск -Для быстрого запуска Packmate следует использовать [этот стартер](https://gitlab.com/packmate/starter/-/blob/master/README.md). +Для быстрого запуска 0xb00b5 team Packmate следует использовать [этот стартер](https://gitlab.com/packmate/starter/-/blob/master/README.md). ## Полный запуск -Ниже следует инструкция для тех, кто хочет собрать Packmate самостоятельно. +Ниже следует инструкция для тех, кто хочет собрать 0xb00b5 team Packmate самостоятельно. ### Клонирование Поскольку этот репозиторий содержит фронтенд как git submodule, его необходимо клонировать так: @@ -56,7 +60,7 @@ git submodule update --init --recursive sudo docker compose up --build -d ``` -При успешном запуске Packmate будет видно с любого хоста на порту `65000`. +При успешном запуске 0xb00b5 team Packmate будет видно с любого хоста на порту `65000`. БД будет слушать на порту 65001, но будет разрешать подключения только с localhost. ## Использование @@ -64,5 +68,5 @@ sudo docker compose up --build -d
-*desu~* +*@danosito*
diff --git a/README_EN.md b/README_EN.md index 6384dde..3505f19 100644 --- a/README_EN.md +++ b/README_EN.md @@ -1,10 +1,10 @@
-# Packmate +# 0xb00b5 team Packmate
### [EN | [RU](README.md)] -Advanced network traffic flow analyzer for A/D CTFs. +Advanced network traffic flow analyzer for A/D CTFs with a pixel-neon twist. #### Features: * Can monitor live traffic or analyze pcap files @@ -23,14 +23,18 @@ Advanced network traffic flow analyzer for A/D CTFs. * Can automatically decompress GZIPed HTTP * Can automatically deflate WebSockets with permessages-deflate extension * Can automatically decrypt TLS with RSA using given private key (like Wireshark) +* Decoy login for `admin:admin` with `fun` and `fake_packets` modes so snoopers never see the real data ![Main window](screenshots/Screenshot.png) +### Admin:admin decoy +The admin:admin credentials now trigger a decoy (enabled by default). Configure it via `PACKMATE_FAKE_ADMIN_ENABLED` and `PACKMATE_FAKE_ADMIN_MODE` (`fun` or `fake_packets`) to keep everyone away from the real interface. + ## Quick Start -To quickly start using Packmate, use [this starter](https://gitlab.com/packmate/starter/-/blob/master/README_EN.md). +To quickly start using 0xb00b5 team Packmate, use [this starter](https://gitlab.com/packmate/starter/-/blob/master/README_EN.md). ## Full Build -Below are the instructions for those who want to build Packmate on their own. +Below are the instructions for those who want to build 0xb00b5 team Packmate on their own. ### Cloning As this repository contains frontend part as a git submodule, it has to be cloned like this: @@ -56,7 +60,7 @@ After filling in env file you can launch the app: sudo docker-compose up --build -d ``` -If everything went fine, Packmate will be available on port `65000` from any host. +If everything went fine, 0xb00b5 team Packmate will be available on port `65000` from any host. Database with listen on port 65001, but will only accept connections from localhost. ## Usage diff --git a/docker-compose.yml b/docker-compose.yml index cb42a90..ce7b484 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,6 +8,8 @@ services: PCAP_FILE: ${PACKMATE_PCAP_FILE:-} WEB_LOGIN: ${PACKMATE_WEB_LOGIN:-BinaryBears} WEB_PASSWORD: ${PACKMATE_WEB_PASSWORD:-123456} + FAKE_ADMIN_AUTH_ENABLED: ${PACKMATE_FAKE_ADMIN_ENABLED:-true} + FAKE_ADMIN_MODE: ${PACKMATE_FAKE_ADMIN_MODE:-fun} OLD_STREAMS_CLEANUP_ENABLED: ${PACKMATE_OLD_STREAMS_CLEANUP_ENABLED:-false} OLD_STREAMS_CLEANUP_INTERVAL: ${PACKMATE_OLD_STREAMS_CLEANUP_INTERVAL:-5} OLD_STREAMS_CLEANUP_THRESHOLD: ${PACKMATE_OLD_STREAMS_CLEANUP_THRESHOLD:-240} @@ -43,4 +45,4 @@ services: test: [ "CMD-SHELL", "pg_isready -U packmate -p 65001" ] interval: 2s timeout: 5s - retries: 15 \ No newline at end of file + retries: 15 diff --git a/docker/Dockerfile_app b/docker/Dockerfile_app index e35243e..dcf2c97 100644 --- a/docker/Dockerfile_app +++ b/docker/Dockerfile_app @@ -20,10 +20,12 @@ CMD [ "java", "-Djava.net.preferIPv4Stack=true", "-Djava.net.preferIPv4Addresses "--packmate.capture-mode=${MODE}", "--packmate.pcap-file=${PCAP_FILE}", \ "--packmate.interface-name=${INTERFACE}", "--packmate.local-ip=${LOCAL_IP}", \ "--packmate.web.account-login=${WEB_LOGIN}", "--packmate.web.account-password=${WEB_PASSWORD}", \ + "--packmate.web.fake-admin.enabled=${FAKE_ADMIN_AUTH_ENABLED}", \ + "--packmate.web.fake-admin.mode=${FAKE_ADMIN_MODE}", \ "--packmate.cleanup.enabled=${OLD_STREAMS_CLEANUP_ENABLED}", \ "--packmate.cleanup.interval=${OLD_STREAMS_CLEANUP_INTERVAL}", \ "--packmate.cleanup.threshold=${OLD_STREAMS_CLEANUP_THRESHOLD}", \ "--server.port=65000", "--server.address=0.0.0.0" \ ] -EXPOSE 65000 \ No newline at end of file +EXPOSE 65000 diff --git a/docs/SETUP.md b/docs/SETUP.md index d7c67ff..93c59e2 100644 --- a/docs/SETUP.md +++ b/docs/SETUP.md @@ -1,6 +1,6 @@ ## Настройка -Packmate использует настройки из файла `.env` (в той же папке, что и `docker-compose.yml`) +0xb00b5 team Packmate использует настройки из файла `.env` (в той же папке, что и `docker-compose.yml`) ### Основные настройки ```dotenv @@ -10,13 +10,17 @@ PACKMATE_LOCAL_IP=10.20.1.1 PACKMATE_WEB_LOGIN=SomeUser # Пароль для web-авторизации PACKMATE_WEB_PASSWORD=SomeSecurePassword +# Включает обманку при вводе admin:admin +PACKMATE_FAKE_ADMIN_ENABLED=true +# fun или fake_packets - варианты обманки +PACKMATE_FAKE_ADMIN_MODE=fun ``` ### Режим работы -Packmate поддерживает три основных режима работы: `LIVE`, `FILE` и `VIEW`. -1. `LIVE` - это основной режим работы во время CTF. Packmate обрабатывает живой трафик и сразу выводит результаты. -2. `FILE` - обрабатывает трафик из pcap файлов. Полезен для анализа трафика с прошедших CTF, где не был запущен Packmate, или тех, где невозможно запустить его на вулнбоксе. -3. `VIEW` - Packmate не обрабатывает трафик, а только показывает уже обработанные стримы. Полезен для разборов после завершения CTF. +0xb00b5 team Packmate поддерживает три основных режима работы: `LIVE`, `FILE` и `VIEW`. +1. `LIVE` - это основной режим работы во время CTF. 0xb00b5 team Packmate обрабатывает живой трафик и сразу выводит результаты. +2. `FILE` - обрабатывает трафик из pcap файлов. Полезен для анализа трафика с прошедших CTF, где не был запущен 0xb00b5 team Packmate, или тех, где невозможно запустить его на вулнбоксе. +3. `VIEW` - 0xb00b5 team Packmate не обрабатывает трафик, а только показывает уже обработанные стримы. Полезен для разборов после завершения CTF.
Настройка LIVE @@ -62,7 +66,7 @@ PACKMATE_MODE=VIEW
### Очистка БД -На крупных CTF через какое-то время накапливается большое количество трафика. Это замедляет работу Packmate и занимает много места на диске. +На крупных CTF через какое-то время накапливается большое количество трафика. Это замедляет работу 0xb00b5 team Packmate и занимает много места на диске. Для оптимизации работы, рекомендуется включить регулярную очистку БД от старых стримов. Это будет работать только в режиме `LIVE`. ```dotenv @@ -79,11 +83,11 @@ PACKMATE_OLD_STREAMS_CLEANUP_THRESHOLD=240 ```dotenv # Пароль от БД. Из-за того, что БД принимает подключения только с localhost, менять его необязательно, но можно, для дополнительной безопасности. PACKMATE_DB_PASSWORD=K604YnL3G1hp2RDkCZNjGpxbyNpNHTRb -# Версия Packmate. Можно изменить, если нужно использовать другой образ из docker registry. +# Версия 0xb00b5 team Packmate. Можно изменить, если нужно использовать другой образ из docker registry. BUILD_TAG=latest ``` Чтобы использовать расшифровку TLS (с RSA), нужно положить соответствующий приватный ключ, который использовался для генерации сертификата, в папку `rsa_keys`. -Файлы БД сохраняются в ./data, поэтому для обнуления базы нужно удалить эту папку. \ No newline at end of file +Файлы БД сохраняются в ./data, поэтому для обнуления базы нужно удалить эту папку. diff --git a/docs/SETUP_EN.md b/docs/SETUP_EN.md index 6b12da6..ad5f48c 100644 --- a/docs/SETUP_EN.md +++ b/docs/SETUP_EN.md @@ -1,6 +1,6 @@ ## Setup -Packmate uses properties from the `.env` file (in the same directory as `docker-compose.yml`) +0xb00b5 team Packmate uses properties from the `.env` file (in the same directory as `docker-compose.yml`) ### Primary settings ```dotenv @@ -10,13 +10,17 @@ PACKMATE_LOCAL_IP=10.20.1.1 PACKMATE_WEB_LOGIN=SomeUser # Password for the web interface PACKMATE_WEB_PASSWORD=SomeSecurePassword +# Enable decoy flow for admin:admin login +PACKMATE_FAKE_ADMIN_ENABLED=true +# fun or fake_packets - pick the decoy flavor +PACKMATE_FAKE_ADMIN_MODE=fun ``` ### Modes of operation -Packmate supports 3 modes of operation: `LIVE`, `FILE` и `VIEW`. -1. `LIVE` - the usual mode during a CTF. Packmate processes live traffic and instantly displays the results. -2. `FILE` - processes traffic from pcap files. Useful to analyze traffic from past CTFs where Packmate wasn't launched, or CTFs where it's impossible to use it on the vulnbox. -3. `VIEW` - Packmate does not process any traffic, but simply shows already processed streams. Useful for post-game analyses. +0xb00b5 team Packmate supports 3 modes of operation: `LIVE`, `FILE` и `VIEW`. +1. `LIVE` - the usual mode during a CTF. 0xb00b5 team Packmate processes live traffic and instantly displays the results. +2. `FILE` - processes traffic from pcap files. Useful to analyze traffic from past CTFs where 0xb00b5 team Packmate wasn't launched, or CTFs where it's impossible to use it on the vulnbox. +3. `VIEW` - 0xb00b5 team Packmate does not process any traffic, but simply shows already processed streams. Useful for post-game analyses.
LIVE setup @@ -62,7 +66,7 @@ PACKMATE_MODE=VIEW
### Database cleanup -On large CTFsб after some time a lot of traffic will pile up. This can slow Packmate down and take a lot of drive space. +On large CTFsб after some time a lot of traffic will pile up. This can slow 0xb00b5 team Packmate down and take a lot of drive space. To optimize the workflow, it is recommended to enable periodical database cleanup of old streams. It will only work in the `LIVE` mode. ```dotenv @@ -79,10 +83,10 @@ PACKMATE_OLD_STREAMS_CLEANUP_THRESHOLD=240 ```dotenv # Database password. Considering it only listens on localhost, it's not mandatory to change it, but you can do it for additional security. PACKMATE_DB_PASSWORD=K604YnL3G1hp2RDkCZNjGpxbyNpNHTRb -# Packmate version. Change it if you want to use a different version from the docker registry. +# 0xb00b5 team Packmate version. Change it if you want to use a different version from the docker registry. BUILD_TAG=latest ``` To use the TLS decryption, you have to put the matching private key in the `rsa_keys` directory. -Database files are being saved in `./data`, so to reset the database, you need to delete this directory. \ No newline at end of file +Database files are being saved in `./data`, so to reset the database, you need to delete this directory. diff --git a/frontend b/frontend index 8f23d97..f90217c 160000 --- a/frontend +++ b/frontend @@ -1 +1 @@ -Subproject commit 8f23d97100f11cd6671bb62aca5ce9b6a898b865 +Subproject commit f90217cd6cb03dfafcec6476d4f862784b4a8184 diff --git a/src/main/java/ru/serega6531/packmate/configuration/SecurityConfiguration.java b/src/main/java/ru/serega6531/packmate/configuration/SecurityConfiguration.java index f24f32d..f200e90 100644 --- a/src/main/java/ru/serega6531/packmate/configuration/SecurityConfiguration.java +++ b/src/main/java/ru/serega6531/packmate/configuration/SecurityConfiguration.java @@ -7,13 +7,20 @@ import org.springframework.context.event.EventListener; import org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; import ru.serega6531.packmate.properties.PackmateProperties; +import ru.serega6531.packmate.security.FakeAdminAuthFilter; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; @Configuration @EnableWebSecurity @@ -22,31 +29,46 @@ public class SecurityConfiguration { @Bean public InMemoryUserDetailsManager userDetailsService(PackmateProperties properties, PasswordEncoder passwordEncoder) { - UserDetails user = User.builder() + List users = new ArrayList<>(); + + users.add(User.builder() .username(properties.web().accountLogin()) .password(passwordEncoder.encode(properties.web().accountPassword())) .roles("USER") - .build(); + .build()); - return new InMemoryUserDetailsManager(user); + Optional.ofNullable(properties.web().fakeAdmin()) + .filter(PackmateProperties.FakeAdminProperties::enabled) + .ifPresent(fakeAdmin -> users.add(User.builder() + .username("admin") + .password(passwordEncoder.encode("admin")) + .roles("FAKE") + .build())); + + return new InMemoryUserDetailsManager(users); } @Bean - public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + public SecurityFilterChain filterChain(HttpSecurity http, FakeAdminAuthFilter fakeAdminAuthFilter) throws Exception { return http.csrf() .disable() .authorizeHttpRequests((auth) -> - auth.requestMatchers("/site.webmanifest") + auth.requestMatchers("/site.webmanifest", "/fake-admin/**", "/fake/**", "/api/fake/**") .permitAll() + .requestMatchers("/api/**", "/ws/**") + .hasRole("USER") .anyRequest() .authenticated() ) + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() .httpBasic() .and() .headers() .frameOptions() .sameOrigin() .and() + .addFilterAfter(fakeAdminAuthFilter, BasicAuthenticationFilter.class) .build(); } diff --git a/src/main/java/ru/serega6531/packmate/controller/FakeAdminController.java b/src/main/java/ru/serega6531/packmate/controller/FakeAdminController.java new file mode 100644 index 0000000..c4b8861 --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/controller/FakeAdminController.java @@ -0,0 +1,27 @@ +package ru.serega6531.packmate.controller; + +import lombok.RequiredArgsConstructor; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import ru.serega6531.packmate.security.FakeAdminResponder; + +@RestController +@RequestMapping("/fake-admin") +@RequiredArgsConstructor +public class FakeAdminController { + + private final FakeAdminResponder responder; + + @GetMapping(value = "/fun", produces = MediaType.TEXT_HTML_VALUE) + public ResponseEntity fun() { + return ResponseEntity.ok(responder.funPageHtml()); + } + + @GetMapping(value = "/fakePackets", produces = MediaType.TEXT_HTML_VALUE) + public ResponseEntity fakePackets() { + return ResponseEntity.ok(responder.fakePacketsHtml()); + } +} diff --git a/src/main/java/ru/serega6531/packmate/controller/FakeFacadeController.java b/src/main/java/ru/serega6531/packmate/controller/FakeFacadeController.java new file mode 100644 index 0000000..5d66262 --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/controller/FakeFacadeController.java @@ -0,0 +1,23 @@ +package ru.serega6531.packmate.controller; + +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import ru.serega6531.packmate.model.pojo.FakeServiceDto; +import ru.serega6531.packmate.service.ServicesService; + +import java.util.List; + +@RestController +@RequestMapping("/api/fake/") +@RequiredArgsConstructor +public class FakeFacadeController { + + private final ServicesService servicesService; + + @GetMapping("services") + public List getServices() { + return servicesService.findAllForFakeFacade(); + } +} diff --git a/src/main/java/ru/serega6531/packmate/model/enums/FakeAdminMode.java b/src/main/java/ru/serega6531/packmate/model/enums/FakeAdminMode.java new file mode 100644 index 0000000..e84d388 --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/model/enums/FakeAdminMode.java @@ -0,0 +1,6 @@ +package ru.serega6531.packmate.model.enums; + +public enum FakeAdminMode { + FUN, + FAKE_PACKETS +} diff --git a/src/main/java/ru/serega6531/packmate/model/pojo/FakeServiceDto.java b/src/main/java/ru/serega6531/packmate/model/pojo/FakeServiceDto.java new file mode 100644 index 0000000..7ab4f7d --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/model/pojo/FakeServiceDto.java @@ -0,0 +1,12 @@ +package ru.serega6531.packmate.model.pojo; + +import lombok.Builder; +import lombok.Value; + +@Value +@Builder +public class FakeServiceDto { + int port; + String name; + String packetKind; +} diff --git a/src/main/java/ru/serega6531/packmate/properties/PackmateProperties.java b/src/main/java/ru/serega6531/packmate/properties/PackmateProperties.java index 90fafc9..27ca9d3 100644 --- a/src/main/java/ru/serega6531/packmate/properties/PackmateProperties.java +++ b/src/main/java/ru/serega6531/packmate/properties/PackmateProperties.java @@ -3,6 +3,7 @@ package ru.serega6531.packmate.properties; import org.springframework.boot.context.properties.ConfigurationProperties; import ru.serega6531.packmate.model.enums.CaptureMode; +import ru.serega6531.packmate.model.enums.FakeAdminMode; import java.net.InetAddress; @@ -20,7 +21,13 @@ public record PackmateProperties( public record WebProperties( String accountLogin, - String accountPassword + String accountPassword, + FakeAdminProperties fakeAdmin + ) {} + + public record FakeAdminProperties( + boolean enabled, + FakeAdminMode mode ) {} public record TimeoutProperties( diff --git a/src/main/java/ru/serega6531/packmate/security/FakeAdminAuthFilter.java b/src/main/java/ru/serega6531/packmate/security/FakeAdminAuthFilter.java new file mode 100644 index 0000000..0f1a02a --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/security/FakeAdminAuthFilter.java @@ -0,0 +1,77 @@ +package ru.serega6531.packmate.security; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpHeaders; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; +import ru.serega6531.packmate.model.enums.FakeAdminMode; +import ru.serega6531.packmate.properties.PackmateProperties; + +import java.io.IOException; +import java.util.Optional; + +@Slf4j +@RequiredArgsConstructor +@Component +public class FakeAdminAuthFilter extends OncePerRequestFilter { + + private final PackmateProperties properties; + + @Override + protected boolean shouldNotFilter(HttpServletRequest request) { + if (!isFakeEnabled()) { + return true; + } + + String path = request.getRequestURI(); + return path.startsWith("/fake-admin") + || path.startsWith("/api/fake") + || path.startsWith("/fake/") + || path.equals("/favicon.ico"); + } + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + if (!isFakeEnabled()) { + filterChain.doFilter(request, response); + return; + } + + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + boolean isFakeAdmin = authentication != null && authentication.isAuthenticated() + && authentication.getAuthorities().stream().anyMatch(a -> a.getAuthority().equals("ROLE_FAKE")); + + if (isFakeAdmin) { + FakeAdminMode mode = Optional.ofNullable(properties.web().fakeAdmin()) + .map(PackmateProperties.FakeAdminProperties::mode) + .orElse(FakeAdminMode.FUN); + String target = "/fake-admin/" + resolvePath(mode); + log.info("Redirecting fake admin to {}", target); + response.setStatus(HttpServletResponse.SC_TEMPORARY_REDIRECT); + response.setHeader(HttpHeaders.LOCATION, target); + return; + } + + filterChain.doFilter(request, response); + } + + private boolean isFakeEnabled() { + return Optional.ofNullable(properties.web().fakeAdmin()) + .map(PackmateProperties.FakeAdminProperties::enabled) + .orElse(false); + } + + private String resolvePath(FakeAdminMode mode) { + return switch (mode) { + case FAKE_PACKETS -> "fakePackets"; + case FUN -> "fun"; + }; + } +} diff --git a/src/main/java/ru/serega6531/packmate/security/FakeAdminResponder.java b/src/main/java/ru/serega6531/packmate/security/FakeAdminResponder.java new file mode 100644 index 0000000..43b9512 --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/security/FakeAdminResponder.java @@ -0,0 +1,469 @@ +package ru.serega6531.packmate.security; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.stereotype.Component; +import org.springframework.util.StreamUtils; + +import java.io.IOException; +import java.net.URLConnection; +import java.util.Arrays; +import java.util.Base64; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +@Slf4j +@Component +public class FakeAdminResponder { + + private final ObjectMapper mapper = new ObjectMapper(); + private final List encodedImages; + + public FakeAdminResponder() { + this.encodedImages = loadImages(); + } + + private List loadImages() { + try { + Resource[] resources = new PathMatchingResourcePatternResolver() + .getResources("classpath:/static/fake/images/*"); + + List images = Arrays.stream(resources) + .map(resource -> { + try { + String contentType = URLConnection.guessContentTypeFromName(resource.getFilename()); + if (contentType == null) { + contentType = "image/jpeg"; + } + byte[] raw = StreamUtils.copyToByteArray(resource.getInputStream()); + return "data:%s;base64,%s".formatted( + contentType, + Base64.getEncoder().encodeToString(raw)); + } catch (IOException e) { + log.warn("Failed to load fake admin image {}", resource.getFilename(), e); + return null; + } + }) + .filter(Objects::nonNull) + .toList(); + + if (images.isEmpty()) { + log.warn("No images found for fake admin fun mode"); + } + + return images; + } catch (IOException e) { + log.warn("Failed to load fake admin images", e); + return Collections.emptyList(); + } + } + + public String funPageHtml() { + String phrases = toJson(getFunPhrases()); + String images = toJson(encodedImages); + return """ + + + + + 0xb00b5 team Packmate // fake funwall + + + +
+
+

0xb00b5 team Packmate | admin:admin illusion

+
mode: FUN // @danosito
+ +
+ +
+ +
+ + + + """.formatted(phrases, images); + } + + public String fakePacketsHtml() { + return """ + + + + + 0xb00b5 team Packmate // fake packets + + + + +
+
+ +
You're stupid:)
+ + + + """; + } + + private List getFunPhrases() { + return List.of( + "Here's the flag. Are you ready? here it goes... Wait, no.", + "Wanna see the flag? send yours to @danosito:)", + "Hey, why are you here? go pentest our services", + "Hmmm i think might work..", + "Bip, boop, here was packet but codex ate it", + "Our LLM tockens ran out. Maybe you could give us some:)?", + ":(){ :|:& };:", + "i think creds are admin:admin but i'm not sure...", + "Try eternalBlue, i think it would work", + "I think i defended this page well enough, here is flag: LLMDELETEDTHEFLAG=", + "Go open ida pro and reverse this text", + "I would give you our flags for free, but you are a bad person:(", + "b00b5 is not a fresh meat:(", + "marcus, send your packmate credits pls", + "Marcus, fuck off", + "Your special guide to get flag!" + ); + } + + private String toJson(List data) { + try { + return mapper.writeValueAsString(data); + } catch (JsonProcessingException e) { + log.warn("Failed to convert data to json for fake admin", e); + return "[]"; + } + } +} diff --git a/src/main/java/ru/serega6531/packmate/service/ServicesService.java b/src/main/java/ru/serega6531/packmate/service/ServicesService.java index 2fb7358..a643f2e 100644 --- a/src/main/java/ru/serega6531/packmate/service/ServicesService.java +++ b/src/main/java/ru/serega6531/packmate/service/ServicesService.java @@ -14,6 +14,7 @@ import ru.serega6531.packmate.model.pojo.ServiceCreateDto; import ru.serega6531.packmate.model.pojo.ServiceDto; import ru.serega6531.packmate.model.pojo.ServiceUpdateDto; import ru.serega6531.packmate.model.pojo.SubscriptionMessage; +import ru.serega6531.packmate.model.pojo.FakeServiceDto; import ru.serega6531.packmate.repository.ServiceRepository; import java.net.InetAddress; @@ -79,6 +80,17 @@ public class ServicesService { .toList(); } + public List findAllForFakeFacade() { + return services.values() + .stream() + .map(s -> FakeServiceDto.builder() + .port(s.getPort()) + .name(s.getName()) + .packetKind(s.isHttp() || s.isParseWebSockets() ? "tcp/http" : "tcp") + .build()) + .toList(); + } + public void deleteByPort(int port) { log.info("Removed service at port {}", port); diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 274a3a3..45d7f12 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -27,6 +27,9 @@ packmate: web: account-login: BinaryBears account-password: 123456 + fake-admin: + enabled: true + mode: fun # fun, fake_packets timeout: udp-stream-timeout: 20 # seconds tcp-stream-timeout: 40 # seconds @@ -35,4 +38,4 @@ packmate: enabled: true threshold: 240 # minutes interval: 5 # minutes - ignore-empty-packets: true \ No newline at end of file + ignore-empty-packets: true diff --git a/src/main/resources/static/fake/images/adminAdminMeme.jpg b/src/main/resources/static/fake/images/adminAdminMeme.jpg new file mode 100644 index 0000000..944615b Binary files /dev/null and b/src/main/resources/static/fake/images/adminAdminMeme.jpg differ diff --git a/src/main/resources/static/fake/images/anotherAdminAdminMeme.jpg b/src/main/resources/static/fake/images/anotherAdminAdminMeme.jpg new file mode 100644 index 0000000..a9ce107 Binary files /dev/null and b/src/main/resources/static/fake/images/anotherAdminAdminMeme.jpg differ diff --git a/src/main/resources/static/fake/images/pudge.jpg b/src/main/resources/static/fake/images/pudge.jpg new file mode 100644 index 0000000..565bbcc Binary files /dev/null and b/src/main/resources/static/fake/images/pudge.jpg differ diff --git a/src/main/resources/static/fake/images/sorokin.jpg b/src/main/resources/static/fake/images/sorokin.jpg new file mode 100644 index 0000000..86af6b8 Binary files /dev/null and b/src/main/resources/static/fake/images/sorokin.jpg differ diff --git a/src/main/resources/static/fake/images/typicalInfosec.jpg b/src/main/resources/static/fake/images/typicalInfosec.jpg new file mode 100644 index 0000000..affd133 Binary files /dev/null and b/src/main/resources/static/fake/images/typicalInfosec.jpg differ