Skip to content

Commit 27254d7

Browse files
committed
Add commands
1 parent 6c37472 commit 27254d7

16 files changed

Lines changed: 87 additions & 34 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
![Icon](https://raw.githubusercontent.com/SimonSchubert/LinuxCommandLibrary/master/art/web_hi_res_144.png)
44

5-
The app currently has **5347** manual pages, **23+** basic categories and a bunch of general terminal tips. It works 100% offline, doesn't need an internet connection and has no tracking software.
5+
The app currently has **6005** manual pages, **23+** basic categories and a bunch of general terminal tips. It works 100% offline, doesn't need an internet connection and has no tracking software.
66

77
[![Play Store](https://raw.githubusercontent.com/SimonSchubert/LinuxCommandBibliotheca/master/art/play_store_badge.png)](https://play.google.com/store/apps/details?id=com.inspiredandroid.linuxcommandbibliotheca)
88
[![F-Droid](https://raw.githubusercontent.com/SimonSchubert/LinuxCommandBibliotheca/master/art/fdroid_badge.png)](https://f-droid.org/en/packages/com.inspiredandroid.linuxcommandbibliotheca/)

android/src/main/java/com/inspiredandroid/linuxcommandbibliotheca/data/TipsRepository.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ class TipsRepository(private val context: Context) {
7474
}
7575
}
7676
}
77+
7778
line.trim().startsWith("```") && line.trim().endsWith("```") -> {
7879
// Markdown inline code block
7980
val codeContent = line.trim().removeSurrounding("```")
@@ -86,6 +87,7 @@ class TipsRepository(private val context: Context) {
8687
)
8788
i++
8889
}
90+
8991
line.trim().isNotEmpty() -> {
9092
// Plain text with potential bold formatting
9193
val cleanText = cleanHtmlText(line.trim())
@@ -94,6 +96,7 @@ class TipsRepository(private val context: Context) {
9496
}
9597
i++
9698
}
99+
97100
else -> {
98101
i++
99102
}

android/src/main/java/com/inspiredandroid/linuxcommandbibliotheca/ui/composables/CommandView.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ fun CommandView(
6464
is CommandElement.Text -> {
6565
appendWithHighlight(element.text, searchText, highlightColor)
6666
}
67+
6768
is CommandElement.Man -> {
6869
val start = this.length
6970
withStyle(style = SpanStyle(color = codeColor)) {
@@ -81,6 +82,7 @@ fun CommandView(
8182
end,
8283
)
8384
}
85+
8486
is CommandElement.Url -> {
8587
val start = this.length
8688
withStyle(style = SpanStyle(color = codeColor)) {

android/src/main/java/com/inspiredandroid/linuxcommandbibliotheca/ui/composables/TableView.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,16 +94,19 @@ fun TableView(
9494
cellElements.forEach { element ->
9595
when (element) {
9696
is TextElement.Plain -> append(element.text)
97+
9798
is TextElement.Bold -> {
9899
withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) {
99100
append(element.text)
100101
}
101102
}
103+
102104
is TextElement.Italic -> {
103105
withStyle(style = SpanStyle(fontStyle = FontStyle.Italic)) {
104106
append(element.text)
105107
}
106108
}
109+
107110
is TextElement.Man -> {
108111
val start = this.length
109112
withStyle(style = SpanStyle(color = codeColor)) {

android/src/main/java/com/inspiredandroid/linuxcommandbibliotheca/ui/composables/TipSectionContent.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,19 @@ fun buildTextElementString(elements: List<TextElement>): AnnotatedString = build
3636
elements.forEach { textElement ->
3737
when (textElement) {
3838
is TextElement.Plain -> append(textElement.text)
39+
3940
is TextElement.Bold -> {
4041
withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) {
4142
append(textElement.text)
4243
}
4344
}
45+
4446
is TextElement.Italic -> {
4547
withStyle(style = SpanStyle(fontStyle = FontStyle.Italic)) {
4648
append(textElement.text)
4749
}
4850
}
51+
4952
is TextElement.Man -> append(textElement.man)
5053
}
5154
}

android/src/main/java/com/inspiredandroid/linuxcommandbibliotheca/ui/composables/TopBar.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,8 +341,11 @@ private fun getTitleByRoute(backStackEntry: NavBackStackEntry?): String {
341341
}
342342
return when (val route = backStackEntry.destination.route) {
343343
"commands" -> stringResource(R.string.commands)
344+
344345
"basics" -> stringResource(R.string.basics)
346+
345347
"tips" -> stringResource(R.string.tips)
348+
346349
else -> {
347350
if (route?.startsWith("command?") == true) {
348351
backStackEntry.arguments?.getString("commandName") ?: ""

android/src/main/java/com/inspiredandroid/linuxcommandbibliotheca/ui/screens/commanddetail/CommandDetailScreen.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ private fun CommandSectionColumn(
106106
seeAlsoCommands = seeAlsoCommands,
107107
onNavigate = onNavigate,
108108
)
109+
109110
else -> DefaultSectionContent(content = section.content, onNavigate = onNavigate)
110111
}
111112
}

assets/commands/getnpusers.py.md

Lines changed: 40 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,76 @@
11
# TLDR
22

3-
**Query AS-REP roastable** users
3+
**Query domain users** with Kerberos pre-auth disabled (with credentials)
44

5-
```GetNPUsers.py [domain]/[username] -dc-ip [dc_ip]```
5+
```GetNPUsers.py [DOMAIN]/[username]:[password] -request -format hashcat -outputfile [hashes.txt]```
66

7-
**No preauth enumeration**
7+
**Check specific users** from a file (no credentials needed)
88

9-
```GetNPUsers.py [domain]/ -usersfile [users.txt] -dc-ip [dc_ip]```
9+
```GetNPUsers.py [DOMAIN]/ -usersfile [users.txt] -format hashcat -outputfile [hashes.txt] -dc-ip [DC_IP]```
1010

11-
**Request TGT**
11+
**Request TGT for a specific user** without password
1212

13-
```GetNPUsers.py [domain]/[username]:[password] -dc-ip [dc_ip] -request```
13+
```GetNPUsers.py [DOMAIN]/[username] -no-pass -dc-ip [DC_IP]```
1414

15-
**Output hashcat format**
15+
**Use pass-the-hash** authentication
1616

17-
```GetNPUsers.py [domain]/ -usersfile [users.txt] -format hashcat -dc-ip [dc_ip]```
17+
```GetNPUsers.py [DOMAIN]/[username] -hashes [LMhash]:[NThash] -request```
1818

19-
# SYNOPSIS
19+
**Output in John format** for cracking
2020

21-
**GetNPUsers.py** [_domain_]/[_user_] [_options_]
21+
```GetNPUsers.py [DOMAIN]/[username]:[password] -request -format john```
2222

23-
# PARAMETERS
23+
# SYNOPSIS
2424

25-
_DOMAIN/USER_
26-
> Domain and username.
25+
**GetNPUsers.py** [_DOMAIN_]/[_USER_]:[_PASSWORD_] [_OPTIONS_]
2726

28-
**-dc-ip** _IP_
29-
> Domain controller IP.
27+
**GetNPUsers.py** [_DOMAIN_]/ **-usersfile** _FILE_ [_OPTIONS_]
3028

31-
**-usersfile** _FILE_
32-
> File with usernames.
29+
# PARAMETERS
3330

3431
**-request**
35-
> Request TGT.
32+
> Request TGT for users found with pre-auth disabled.
3633
3734
**-format** _FORMAT_
38-
> Output format: hashcat, john.
35+
> Output format for hashes: hashcat or john.
3936
4037
**-outputfile** _FILE_
41-
> Output file.
38+
> Write AS-REP hashes to specified file.
39+
40+
**-usersfile** _FILE_
41+
> File containing list of usernames to check.
42+
43+
**-dc-ip** _IP_
44+
> IP address of the domain controller.
45+
46+
**-no-pass**
47+
> Use empty password or no password.
48+
49+
**-hashes** _LMHASH_:_NTHASH_
50+
> Use NTLM hash for pass-the-hash authentication.
51+
52+
**-k**
53+
> Use Kerberos authentication from ccache (set KRB5CCNAME).
4254
43-
**--help**
44-
> Display help information.
55+
**-debug**
56+
> Enable debug output.
4557
4658
# DESCRIPTION
4759

48-
**GetNPUsers.py** is an Impacket tool for AS-REP Roasting attacks. It identifies Active Directory users with Kerberos pre-authentication disabled and retrieves their password hashes.
60+
**GetNPUsers.py** is an Impacket tool that identifies Active Directory users with Kerberos pre-authentication disabled and retrieves their AS-REP (Authentication Service Response) encrypted data. This data can be cracked offline to recover user passwords, an attack known as **AS-REP Roasting**.
4961

50-
The tool requests AS-REP responses for users without pre-auth, which contain encrypted data crackable offline. It's used in penetration testing for credential attacks.
62+
When pre-authentication is disabled for a user, anyone can request a TGT on their behalf without knowing the password. The domain controller returns encrypted data using the user's password hash, which can be brute-forced offline.
5163

52-
GetNPUsers.py enables identifying weak configurations in Active Directory.
64+
The tool can query all domain users via LDAP (requires credentials) or check specific usernames from a file (no credentials required if usernames are known).
5365

5466
# CAVEATS
5567

56-
**Authorized testing only.** Requires network access to DC. Results need offline cracking.
68+
This tool is for authorized security testing, CTF competitions, and defensive security research only. Unauthorized use against systems you do not own or have permission to test is illegal. Retrieved hashes require cracking with tools like hashcat (-m 18200) or John the Ripper.
5769

5870
# HISTORY
5971

60-
GetNPUsers.py is part of **Impacket**, the Python network protocol toolkit. It implements AS-REP Roasting attacks documented in Active Directory security research.
72+
GetNPUsers.py is part of **Impacket**, a collection of Python classes for working with network protocols. Impacket was created by SecureAuth (now Fortra) and is widely used in penetration testing and security research. AS-REP Roasting became a well-known attack technique after research into Kerberos pre-authentication weaknesses.
6173

6274
# SEE ALSO
6375

64-
[GetUserSPNs.py](/man/GetUserSPNs.py)(1), [secretsdump.py](/man/secretsdump.py)(1)
76+
[GetUserSPNs.py](/man/GetUserSPNs.py)(1), [secretsdump.py](/man/secretsdump.py)(1), [hashcat](/man/hashcat)(1), [john](/man/john)(1)

cli/src/main/kotlin/com/linuxcommandlibrary/cli/ConsoleApplication.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,13 @@ private fun showStartMenu() {
4444

4545
when (readNumber()) {
4646
0 -> exitProcess(0)
47+
4748
1 -> showSearch()
49+
4850
2 -> showBasicCategories()
51+
4952
3 -> showTips()
53+
5054
else -> {
5155
println("Invalid input")
5256
showStartMenu()
@@ -114,10 +118,12 @@ private fun showSearch() {
114118

115119
when (val choice = readNumber()) {
116120
0 -> showStartMenu()
121+
117122
in 1..commands.size -> {
118123
val name = commands[choice - 1].name
119124
showCommand(name)
120125
}
126+
121127
else -> {
122128
println("Invalid input")
123129
showSearch()
@@ -179,10 +185,12 @@ private fun showBasicCategories() {
179185

180186
when (val choice = readNumber()) {
181187
0 -> showStartMenu()
188+
182189
in 1..categories.size -> {
183190
val id = categories[choice - 1].id
184191
showBasicGroups(id)
185192
}
193+
186194
else -> {
187195
println("Invalid input")
188196
showBasicCategories()
@@ -210,6 +218,7 @@ private fun showBasicGroups(categoryId: String) {
210218
.replace(Regex("\\[([^\\]]+)]\\(/man/[^)]+\\)")) { it.groupValues[1] } // Remove man links
211219
println("- $ $code")
212220
}
221+
213222
else -> {} // Skip non-code sections in basic groups display
214223
}
215224
}
@@ -237,9 +246,11 @@ private fun showTips() {
237246

238247
when (val choice = readNumber()) {
239248
0 -> showStartMenu()
249+
240250
in 1..tips.size -> {
241251
showTipDetail(tips[choice - 1])
242252
}
253+
243254
else -> {
244255
println("Invalid input")
245256
showTips()
@@ -264,6 +275,7 @@ private fun showTipDetail(tip: TipInfo) {
264275
}
265276
println(text)
266277
}
278+
267279
is TipSectionElement.Blockquote -> {
268280
val text = section.elements.joinToString("") { element ->
269281
when (element) {
@@ -275,9 +287,11 @@ private fun showTipDetail(tip: TipInfo) {
275287
}
276288
println(" > $text")
277289
}
290+
278291
is TipSectionElement.Code -> {
279292
println("$ ${section.command}")
280293
}
294+
281295
is TipSectionElement.Table -> {
282296
// Simple table rendering
283297
section.rows.forEach { row ->

common/src/commonMain/kotlin/com/linuxcommandlibrary/shared/App.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ fun String.getCommandList(
6464
val cmd = currentCommand.substring(4).split("|").first()
6565
list.add(CommandElement.Url(cmd, url))
6666
}
67+
6768
else -> {
6869
list.add(CommandElement.Man(currentCommand))
6970
}

0 commit comments

Comments
 (0)