Skip to content
This repository was archived by the owner on Mar 26, 2022. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.93beta5
0.93beta6
15 changes: 13 additions & 2 deletions doc/cntlm.1
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
.SH SYNOPSIS
.B cntlm
[
.B -AaBcDdFfgHhILlMPprSsTUuvw
.B -AaBcDdFfgHhILlMPprSsTUuvwXZ
] [ \fIhost1\fP \fIport1\fP | \fIhost1\fP:\fIport1\fP ] ... \fIhostN\fP \fIportN\fP

.SH DESCRIPTION
Expand Down Expand Up @@ -111,7 +111,7 @@ credentials and it is moderately easy to sniff them.
.ne 6
IMPORTANT: HTTP protocol obviously has means to negotiate authorization before letting you through, but TCP/IP
doesn't (i.e. open port is open port). If you use NTLM-to-basic and DON'T specify some username/password in
the configuration file, you are bound to loose tunneling features, because \fBcntlm\fP alone won't know your
the configuration file, you are bound to lose tunneling features, because \fBcntlm\fP alone won't know your
credentials.

Because NTLM identification has at least three parts (username, password, domain) and the basic authentication
Expand Down Expand Up @@ -360,6 +360,17 @@ Workstation NetBIOS name. Do not use full qualified domain name (FQDN) here. Jus
If not specified, \fBcntlm\fP tries to get the system hostname and if that fails, uses "cntlm" - it's because
some proxies require this field non-empty.

.TP
.B -X <type>
Use \fBSSPI\fP with specified handle type. Works only under Windows. Default is negotiate.

.TP
.B -Z
Requires the \fB-p\fP option. Use this option to get hashes for password-less configuration in JSON format. In this
mode, \fBcntlm\fP prints the results and exits. You ought to use this option with explicit \fB-u\fP and \fB-d\fP,
because some hashes include the username and domain name in the calculation. Do see \fB-a\fP for security
recommendations.

.SH CONFIGURATION
Configuration file is basically an INI file, except there are no "=" between keys and values. It comprises of
whitespace delimited keyword and value pairs. Apart from that, there are sections as well, they have the usual
Expand Down
54 changes: 46 additions & 8 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,7 @@ int main(int argc, char **argv) {
int tracefile = 0;
int cflags = 0;
int asdaemon = 1;
int apihash = 0;
char *myconfig = NULL;
plist_t tunneld_list = NULL;
plist_t proxyd_list = NULL;
Expand Down Expand Up @@ -717,7 +718,7 @@ int main(int argc, char **argv) {
syslog(LOG_INFO, "Starting cntlm version " VERSION " for LITTLE endian\n");
#endif

while ((i = getopt(argc, argv, ":-:T:a:c:d:fghIl:p:r:su:vw:A:BD:F:G:HL:M:N:O:P:R:S:U:X:")) != -1) {
while ((i = getopt(argc, argv, ":-:T:a:c:d:fghIl:p:r:su:vw:A:BD:F:G:HL:M:N:O:P:R:S:U:X:Z")) != -1) {
switch (i) {
case 'A':
case 'D':
Expand Down Expand Up @@ -870,6 +871,9 @@ int main(int argc, char **argv) {
help = 1;
#endif
break;
case 'Z':
apihash = 1;
break;
case 'h':
default:
help = 1;
Expand All @@ -887,7 +891,7 @@ int main(int argc, char **argv) {
"newer. For more information about these matters, see the file LICENSE.\n"
"For copyright holders of included encryption routines see headers.\n\n");

fprintf(stderr, "Usage: %s [-AaBcDdFfgHhILlMPpSsTUuvw] <proxy_host>[:]<proxy_port> ...\n", argv[0]);
fprintf(stderr, "Usage: %s [-AaBcDdFfgHhILlMPpSsTUuvwXZ] <proxy_host>[:]<proxy_port> ...\n", argv[0]);
fprintf(stderr, "\t-A <address>[/<net>]\n"
"\t ACL allow rule. IP or hostname, net must be a number (CIDR notation)\n");
fprintf(stderr, "\t-a ntlm | nt | lm\n"
Expand Down Expand Up @@ -944,7 +948,8 @@ int main(int argc, char **argv) {
"\t Some proxies require correct NetBIOS hostname.\n");
fprintf(stderr, "\t-X <sspi_handle_type>\n"
"\t Use SSPI with specified handle type. Works only under Windows.\n"
"\t Default is negotiate.\n\n");
"\t Default is negotiate.\n");
fprintf(stderr, "\t-Z Generate JSON password hashes for use in APIs (requires -p flag).\n\n");
exit(1);
}

Expand Down Expand Up @@ -1185,10 +1190,10 @@ int main(int argc, char **argv) {

config_close(cf);

if (!interactivehash && !parent_list)
if (!interactivehash && !parent_list && !apihash)
croak("Parent proxy address missing.\n", interactivepwd || magic_detect);

if (!interactivehash && !magic_detect && !proxyd_list)
if (!interactivehash && !magic_detect && !proxyd_list && !apihash)
croak("No proxy service ports were successfully opened.\n", interactivepwd);

/*
Expand Down Expand Up @@ -1266,6 +1271,13 @@ int main(int argc, char **argv) {
printf("\n");
}

if (apihash) {
if (strlen(cpassword) == 0) {
printf("Use '-p' flag to provide a password!\n");
goto bailout;
}
}

/*
* Convert optional PassNT, PassLM and PassNTLMv2 strings to hashes
* unless plaintext pass was used, which has higher priority.
Expand Down Expand Up @@ -1302,15 +1314,15 @@ int main(int argc, char **argv) {
free(tmp);
}
} else {
if (g_creds->hashnt || magic_detect || interactivehash) {
if (g_creds->hashnt || magic_detect || interactivehash || apihash) {
tmp = ntlm_hash_nt_password(cpassword);
auth_memcpy(g_creds, passnt, tmp, 21);
free(tmp);
} if (g_creds->hashlm || magic_detect || interactivehash) {
} if (g_creds->hashlm || magic_detect || interactivehash || apihash) {
tmp = ntlm_hash_lm_password(cpassword);
auth_memcpy(g_creds, passlm, tmp, 21);
free(tmp);
} if (g_creds->hashntlm2 || magic_detect || interactivehash) {
} if (g_creds->hashntlm2 || magic_detect || interactivehash || apihash) {
tmp = ntlm2_hash_password(cuser, cdomain, cpassword);
auth_memcpy(g_creds, passntlm2, tmp, 16);
free(tmp);
Expand Down Expand Up @@ -1362,6 +1374,32 @@ int main(int argc, char **argv) {
goto bailout;
}

if (apihash) {
printf("[");
if (g_creds->passlm) {
tmp = printmem(g_creds->passlm, 16, 8);
printf("{\"PassLM\" : {\"hash\" : \"%s\"}}", tmp);
free(tmp);
}

if (g_creds->passnt) {
if (g_creds -> passlm) { printf(","); }
tmp = printmem(g_creds->passnt, 16, 8);
printf("{\"PassNT\" : {\"hash\" : \"%s\"}}", tmp);
free(tmp);
}

if (g_creds->passntlm2) {
if (g_creds -> passlm || g_creds -> passnt) { printf(","); }
tmp = printmem(g_creds->passntlm2, 16, 8);
printf("{\"PassNTLMv2\" : { \"hash\":\"%s\", \"user\":\"%s\", \"domain\":\"%s\" }}",
tmp, g_creds->user, g_creds->domain);
free(tmp);
}
printf("]\n");
goto bailout;
}

/*
* If we're going to need a password, check we really have it.
*/
Expand Down