1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-06 04:31:29 +00:00

merging nse_openssl branch

This commit is contained in:
sven
2008-10-08 22:21:41 +00:00
parent 70bfb42915
commit d8714befb1
12 changed files with 1250 additions and 177 deletions

View File

@@ -62,9 +62,14 @@ INSTALLNDIFF=@INSTALLNDIFF@
UNINSTALLZENMAP=@UNINSTALLZENMAP@ UNINSTALLZENMAP=@UNINSTALLZENMAP@
ifneq (@LIBLUA_LIBS@,) ifneq (@LIBLUA_LIBS@,)
NSE_SRC=nse_main.cc nse_nsock.cc nse_init.cc nse_fs.cc nse_nmaplib.cc nse_debug.cc nse_pcrelib.cc nse_binlib.cc nse_hash.cc nse_bit.cc NSE_SRC=nse_main.cc nse_nsock.cc nse_init.cc nse_fs.cc nse_nmaplib.cc nse_debug.cc nse_pcrelib.cc nse_binlib.cc nse_bit.cc
NSE_HDRS=nse_main.h nse_nsock.h nse_init.h nse_fs.h nse_nmaplib.h nse_debug.h nse_macros.h nse_pcrelib.h nse_binlib.h nse_hash.h nse_bit.h NSE_HDRS=nse_main.h nse_nsock.h nse_init.h nse_fs.h nse_nmaplib.h nse_debug.h nse_macros.h nse_pcrelib.h nse_binlib.h nse_bit.h
NSE_OBJS=nse_main.o nse_nsock.o nse_init.o nse_fs.o nse_nmaplib.o nse_debug.o nse_pcrelib.o nse_binlib.o nse_hash.o nse_bit.o NSE_OBJS=nse_main.o nse_nsock.o nse_init.o nse_fs.o nse_nmaplib.o nse_debug.o nse_pcrelib.o nse_binlib.o nse_bit.o
ifneq (@OPENSSL_LIBS@,)
NSE_SRC+=nse_openssl.cc
NSE_HDRS+=nse_openssl.h
NSE_OBJS+=nse_openssl.o
endif
endif endif
export SRCS = main.cc nmap.cc targets.cc tcpip.cc nmap_error.cc utils.cc idle_scan.cc osscan.cc osscan2.cc output.cc scan_engine.cc timing.cc charpool.cc services.cc protocols.cc nmap_rpc.cc portlist.cc NmapOps.cc TargetGroup.cc Target.cc FingerPrintResults.cc service_scan.cc NmapOutputTable.cc MACLookup.cc nmap_tty.cc nmap_dns.cc traceroute.cc portreasons.cc $(NSE_SRC) @COMPAT_SRCS@ export SRCS = main.cc nmap.cc targets.cc tcpip.cc nmap_error.cc utils.cc idle_scan.cc osscan.cc osscan2.cc output.cc scan_engine.cc timing.cc charpool.cc services.cc protocols.cc nmap_rpc.cc portlist.cc NmapOps.cc TargetGroup.cc Target.cc FingerPrintResults.cc service_scan.cc NmapOutputTable.cc MACLookup.cc nmap_tty.cc nmap_dns.cc traceroute.cc portreasons.cc $(NSE_SRC) @COMPAT_SRCS@

View File

@@ -1164,6 +1164,233 @@ if(s) code_to_be_done_on_match end
<indexterm class="endofrange" startref="nse-pcre-indexterm"/> <indexterm class="endofrange" startref="nse-pcre-indexterm"/>
</sect2> </sect2>
<sect2 id="nse-openssl">
<indexterm class="startofrange" id="nse-openssl-indexterm"><primary><varname>openssl</varname> NSE module</primary></indexterm>
<indexterm><primary>OpenSSL</primary><secondary>in NSE</secondary></indexterm>
<title>OpenSSL NSE bindings</title>
<para>
The <literal>openssl</literal> module provides functions for
dealing with multiprecision integers. The functions reside inside the
<literal>openssl</literal> namespace.
</para>
<variablelist>
<varlistentry>
<term><option>openssl.bignum_num_bits( bignum )</option></term>
<listitem>
<para>Returns the size of <literal>bignum</literal> in bits.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>openssl.bignum_num_bytes( bignum )</option></term>
<listitem>
<para>Returns the size of <literal>bignum</literal> in bytes.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>openssl.bignum_set_bit( bignum, position )</option></term>
<listitem>
<para>Sets bit at <literal>position</literal> in <literal>bignum</literal>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>openssl.bignum_clear_bit( bignum, position )</option></term>
<listitem>
<para>Clears bit at <literal>position</literal> in <literal>bignum</literal>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>openssl.bignum_is_bit_set( bignum, position )</option></term>
<listitem>
<para>Get bit at <literal>position</literal> in <literal>bignum</literal>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>openssl.bignum_set_negative( bignum, negative )</option></term>
<listitem>
<para>Set sign of <literal>bignum</literal>. If <literal>negative</literal> is <literal>false</literal> the sign becomes positive otherwise it becomes negative.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>openssl.bignum_is_negative( bignum )</option></term>
<listitem>
<para>Check sign of <literal>bignum</literal>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>openssl.bignum_bin2bn( string )</option></term>
<listitem>
<para>Converts binary encoded <literal>string</literal> into a <literal>bignum</literal>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>openssl.bignum_dec2bn( string )</option></term>
<listitem>
<para>Converts decimal encoded <literal>string</literal> into a <literal>bignum</literal>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>openssl.bignum_hex2bn( string )</option></term>
<listitem>
<para>Converts hex-encoded <literal>string</literal> into a <literal>bignum</literal>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>openssl.bignum_bn2bin( bignum )</option></term>
<listitem>
<para>Converts <literal>bignum</literal> into a binary encoded string.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>openssl.bignum_bn2dec( bignum )</option></term>
<listitem>
<para>Converts <literal>bignum</literal> into a decimal encoded string.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>openssl.bignum_bn2hex( bignum )</option></term>
<listitem>
<para>Converts <literal>bignum</literal> into a hex-encoded string.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>openssl.bignum_rand( bits )</option></term>
<listitem>
<para>Returns random <literal>bignum</literal> with <literal>bits</literal> bit size.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>openssl.bignum_pseudo_rand( bits )</option></term>
<listitem>
<para>Returns pseudo random <literal>bignum</literal> with <literal>bits</literal> bit size.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>openssl.bignum_mod_exp( a, p, m )</option></term>
<listitem>
<para>Returns bignum which is the result of <literal>a</literal>^<literal>p</literal> mod <literal>m</literal>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>openssl.rand_bytes( bytes )</option></term>
<listitem>
<para>Returns a string of <literal>bytes</literal> length with random data.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>openssl.rand_pseudo_bytes( bytes )</option></term>
<listitem>
<para>Returns a string of <literal>bytes</literal> length with pseudo random data.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>openssl.md2( message )</option></term>
<listitem>
<para>Returns the MD2 digest of <literal>message</literal>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>openssl.md4( message )</option></term>
<listitem>
<para>Returns the MD4 digest of <literal>message</literal>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>openssl.md5( message )</option></term>
<listitem>
<para>Returns the MD5 digest of <literal>message</literal>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>openssl.sha1( message )</option></term>
<listitem>
<para>Returns the SHA1 digest of <literal>message</literal>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>openssl.ripemd160( message )</option></term>
<listitem>
<para>Returns the RIPEMD160 digest of <literal>message</literal>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>openssl.digest( algorithm, message )</option></term>
<listitem>
<para>Returns the digest specified by <literal>algorithm</literal> of <literal>message</literal>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>openssl.hmac( algorithm, key, message )</option></term>
<listitem>
<para></para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>openssl.encrypt( algorithm, key, iv, data, padding = false )</option></term>
<listitem>
<para>Encrypt <literal>data</literal> with the encryption algorithm <literal>algorithm</literal>, <literal>key</literal> and the initialization vector <literal>iv</literal>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>openssl.decrypt( algorithm, key, iv, data, padding = false )</option></term>
<listitem>
<para>Decrypt <literal>data</literal> with the encryption algorithm <literal>algorithm</literal>, <literal>key</literal> and the initialization vector <literal>iv</literal>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>openssl.supported_ciphers()</option></term>
<listitem>
<para>Returns a table with the names of the supported cipher algorithms.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>openssl.supported_digests()</option></term>
<listitem>
<para>Returns a table with the names of the supported digest algorithms.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>openssl.DES_string_to_key( string data )</option></term>
<listitem>
<para>Converts <literal>data</literal> which must be a 7-byte string into a 8-byte DES key and sets the parity.</para>
</listitem>
</varlistentry>
</variablelist>
<indexterm class="endofrange" startref="nse-openssl-indexterm"/>
</sect2>
<sect2 id="nse-lib-ipOps"> <sect2 id="nse-lib-ipOps">
<title>IP Operations</title> <title>IP Operations</title>
<indexterm><primary><varname>ipOps</varname> NSE module</primary></indexterm> <indexterm><primary><varname>ipOps</varname> NSE module</primary></indexterm>

View File

@@ -291,7 +291,7 @@
> >
</File> </File>
<File <File
RelativePath="..\nse_hash.cc" RelativePath="..\nse_openssl.cc"
> >
</File> </File>
<File <File
@@ -488,7 +488,7 @@
> >
</File> </File>
<File <File
RelativePath="..\nse_hash.h" RelativePath="..\nse_openssl.h"
> >
</File> </File>
<File <File

View File

@@ -1,131 +0,0 @@
#include <ctype.h>
#include <string.h>
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}
#include "nse_hash.h"
#include "nbase/nbase_md5.h"
#include "nbase/nbase_sha1.h"
static int l_md5(lua_State *L)
{
size_t len;
const char *str = luaL_checklstring(L, 1, &len);
MD5_CTX c;
unsigned char digest[MD5_DIGEST_LENGTH];
luaL_Buffer buf;
char hdigit[3];
luaL_buffinit(L,&buf);
if (!nb_MD5_Init(&c)) {
/* ERROR */
luaL_error(L, "MD5 init error");
}
nb_MD5_Update(&c, str, len);
nb_MD5_Final(digest, &c);
for (int ii = 0; ii < MD5_DIGEST_LENGTH; ii++) {
sprintf(hdigit, "%02x", digest[ii]);
luaL_addlstring(&buf, hdigit, 2);
}
luaL_pushresult(&buf);
return 1;
}
static int l_md5bin(lua_State *L)
{
size_t len;
const char *str = luaL_checklstring(L, 1, &len);
MD5_CTX c;
unsigned char digest[MD5_DIGEST_LENGTH];
luaL_Buffer buf;
luaL_buffinit(L,&buf);
if (!nb_MD5_Init(&c)) {
/* ERROR */
luaL_error(L, "MD5 init error");
}
nb_MD5_Update(&c, str, len);
nb_MD5_Final(digest, &c);
lua_pushlstring(L, (char *)digest, MD5_DIGEST_LENGTH);
return 1;
}
static int l_sha1(lua_State *L)
{
size_t len;
const char *str = luaL_checklstring(L, 1, &len);
SHA_CTX c;
unsigned char digest[SHA_DIGEST_LENGTH];
luaL_Buffer buf;
char hdigit[3];
luaL_buffinit(L,&buf);
if (!nb_SHA1_Init(&c)) {
/* ERROR */
luaL_error(L, "sha1 init error");
}
nb_SHA1_Update(&c, str, len);
nb_SHA1_Final(digest, &c);
for (int ii = 0; ii < SHA_DIGEST_LENGTH; ii++) {
sprintf(hdigit, "%02x", digest[ii]);
luaL_addlstring(&buf, hdigit, 2);
}
luaL_pushresult(&buf);
return 1;
}
static int l_sha1bin(lua_State *L)
{
size_t len;
const char *str = luaL_checklstring(L, 1, &len);
SHA_CTX c;
unsigned char digest[SHA_DIGEST_LENGTH];
luaL_Buffer buf;
luaL_buffinit(L,&buf);
if (!nb_SHA1_Init(&c)) {
/* ERROR */
luaL_error(L, "sha1 init error");
}
nb_SHA1_Update(&c, str, len);
nb_SHA1_Final(digest, &c);
lua_pushlstring(L, (char *) digest, SHA_DIGEST_LENGTH);
return 1;
}
static const luaL_reg hashlib[] =
{
{"md5", l_md5},
{"sha1", l_sha1},
{"md5bin", l_md5bin},
{"sha1bin", l_sha1bin},
{NULL, NULL}
};
LUALIB_API int luaopen_hashlib (lua_State *L) {
luaL_register(L, NSE_HASHLIBNAME, hashlib);
return 1;
}

View File

@@ -1,8 +0,0 @@
#ifndef NSE_HASHLIB
#define NSE_HASHLIB
#define NSE_HASHLIBNAME "hash"
LUALIB_API int luaopen_hashlib (lua_State *L);
#endif /* NSE_HASHLIB */

View File

@@ -8,8 +8,11 @@
#include "nse_pcrelib.h" #include "nse_pcrelib.h"
#include "nse_bit.h" #include "nse_bit.h"
#ifdef HAVE_OPENSSL
#include "nse_openssl.h"
#endif
#include "nse_binlib.h" #include "nse_binlib.h"
#include "nse_hash.h"
#include "nbase.h" #include "nbase.h"
@@ -245,8 +248,10 @@ int init_lua (lua_State *L)
{NSE_PCRELIBNAME, luaopen_pcrelib}, // pcre library {NSE_PCRELIBNAME, luaopen_pcrelib}, // pcre library
{"nmap", luaopen_nmap}, // nmap bindings {"nmap", luaopen_nmap}, // nmap bindings
{NSE_BINLIBNAME, luaopen_binlib}, {NSE_BINLIBNAME, luaopen_binlib},
{NSE_HASHLIBNAME, luaopen_hashlib},
{BITLIBNAME, luaopen_bit}, // bit library {BITLIBNAME, luaopen_bit}, // bit library
#ifdef HAVE_OPENSSL
{OPENSSLLIBNAME, luaopen_openssl}, // openssl bindings
#endif
}; };
luaL_openlibs(L); // opens all standard libraries luaL_openlibs(L); // opens all standard libraries

520
nse_openssl.cc Normal file
View File

@@ -0,0 +1,520 @@
#ifdef WIN32
#include "nmap_winconfig.h"
#else
#include "nmap_config.h"
#endif
/* OpenSSL library for lua
* adapted from lmd5 library (http://www.tecgraf.puc-rio.br/~lhf/ftp/lua/)
* Original code written by Luiz Henrique de Figueiredo <lhf@tecgraf.puc-rio.br>
* Adapted for NMap by Thomas Buchanan <tbuchanan@thecompassgrp.net>
* bignum and rand_bytes functions added by Sven Klemm <sven@c3d2.de>
*/
#include <openssl/crypto.h>
#include <openssl/bn.h>
#include <openssl/rand.h>
#include <openssl/md2.h>
#include <openssl/md4.h>
#include <openssl/md5.h>
#include <openssl/sha.h>
#include <openssl/ripemd.h>
#include <openssl/hmac.h>
#include <openssl/des.h>
#include <openssl/evp.h>
#include "nse_openssl.h"
typedef struct bignum_data {
BIGNUM * bn;
} bignum_data_t;
static int l_bignum_bin2bn( lua_State *L ) /** bignum_bin2bn( string s ) */
{
size_t len;
const unsigned char * s = (unsigned char *) luaL_checklstring( L, 1, &len );
BIGNUM * num = BN_new();
BN_bin2bn( s, len, num );
bignum_data_t * data = (bignum_data_t *) lua_newuserdata( L, sizeof(bignum_data_t));
luaL_getmetatable( L, "BIGNUM" );
lua_setmetatable( L, -2 );
data->bn = num;
return 1;
}
static int l_bignum_dec2bn( lua_State *L ) /** bignum_dec2bn( string s ) */
{
const char * s = luaL_checkstring( L, 1 );
BIGNUM * num = BN_new();
BN_dec2bn( &num, s );
bignum_data_t * data = (bignum_data_t *) lua_newuserdata( L, sizeof(bignum_data_t));
luaL_getmetatable( L, "BIGNUM" );
lua_setmetatable( L, -2 );
data->bn = num;
return 1;
}
static int l_bignum_hex2bn( lua_State *L ) /** bignum_hex2bn( string s ) */
{
const char * s = luaL_checkstring( L, 1 );
BIGNUM * num = BN_new();
BN_hex2bn( &num, s );
bignum_data_t * data = (bignum_data_t *) lua_newuserdata( L, sizeof(bignum_data_t));
luaL_getmetatable( L, "BIGNUM" );
lua_setmetatable( L, -2 );
data->bn = num;
return 1;
}
static int l_bignum_rand( lua_State *L ) /** bignum_rand( number bits ) */
{
size_t bits = luaL_checkint( L, 1 );
BIGNUM * num = BN_new();
BN_rand( num, bits, -1, 0 );
bignum_data_t * data = (bignum_data_t *) lua_newuserdata( L, sizeof(bignum_data_t));
luaL_getmetatable( L, "BIGNUM" );
lua_setmetatable( L, -2 );
data->bn = num;
return 1;
}
static int l_bignum_pseudo_rand( lua_State *L ) /** bignum_pseudo_rand( number bits ) */
{
size_t bits = luaL_checkint( L, 1 );
BIGNUM * num = BN_new();
BN_pseudo_rand( num, bits, -1, 0 );
bignum_data_t * data = (bignum_data_t *) lua_newuserdata( L, sizeof(bignum_data_t));
luaL_getmetatable( L, "BIGNUM" );
lua_setmetatable( L, -2 );
data->bn = num;
return 1;
}
static int l_bignum_mod_exp( lua_State *L ) /** bignum_mod_exp( BIGNUM a, BIGNUM p, BIGNUM m ) */
{
bignum_data_t * a = (bignum_data_t *) luaL_checkudata(L, 1, "BIGNUM");
bignum_data_t * p = (bignum_data_t *) luaL_checkudata(L, 2, "BIGNUM");
bignum_data_t * m = (bignum_data_t *) luaL_checkudata(L, 3, "BIGNUM");
BIGNUM * result = BN_new();
BN_CTX * ctx = BN_CTX_new();
BN_CTX_init( ctx );
BN_mod_exp( result, a->bn, p->bn, m->bn, ctx );
BN_CTX_free( ctx );
bignum_data_t * data = (bignum_data_t *) lua_newuserdata( L, sizeof(bignum_data_t));
luaL_getmetatable( L, "BIGNUM" );
lua_setmetatable( L, -2 );
data->bn = result;
return 1;
}
static int l_bignum_num_bits( lua_State *L ) /** bignum_num_bits( BIGNUM bn ) */
{
bignum_data_t * userdata = (bignum_data_t *) luaL_checkudata(L, 1, "BIGNUM");
lua_pushnumber( L, BN_num_bits( userdata->bn) );
return 1;
}
static int l_bignum_num_bytes( lua_State *L ) /** bignum_num_bytes( BIGNUM bn ) */
{
bignum_data_t * userdata = (bignum_data_t *) luaL_checkudata(L, 1, "BIGNUM");
lua_pushnumber( L, BN_num_bytes( userdata->bn) );
return 1;
}
static int l_bignum_set_bit( lua_State *L ) /** bignum_set_bit( BIGNUM bn, number position ) */
{
bignum_data_t * userdata = (bignum_data_t *) luaL_checkudata(L, 1, "BIGNUM");
int position = luaL_checkint( L, 2 );
BN_set_bit( userdata->bn, position );
return 0;
}
static int l_bignum_clear_bit( lua_State *L ) /** bignum_clear_bit( BIGNUM bn, number position ) */
{
bignum_data_t * userdata = (bignum_data_t *) luaL_checkudata(L, 1, "BIGNUM");
int position = luaL_checkint( L, 2 );
BN_clear_bit( userdata->bn, position );
return 0;
}
static int l_bignum_is_bit_set( lua_State *L ) /** bignum_set_bit( BIGNUM bn, number position ) */
{
bignum_data_t * userdata = (bignum_data_t *) luaL_checkudata(L, 1, "BIGNUM");
int position = luaL_checkint( L, 2 );
lua_pushboolean( L, BN_is_bit_set( userdata->bn, position ) );
return 1;
}
static int l_bignum_set_negative( lua_State *L ) /** bignum_set_negative( BIGNUM bn ) */
{
bignum_data_t * userdata = (bignum_data_t *) luaL_checkudata(L, 1, "BIGNUM");
int value = lua_toboolean(L, 2);
BN_set_negative( userdata->bn, value );
return 0;
}
static int l_bignum_is_negative( lua_State *L ) /** bignum_is_negative( BIGNUM bn ) */
{
bignum_data_t * userdata = (bignum_data_t *) luaL_checkudata(L, 1, "BIGNUM");
lua_pushboolean( L, BN_is_negative( userdata->bn) );
return 1;
}
static int l_bignum_bn2bin( lua_State *L ) /** bignum_bn2bin( BIGNUM bn ) */
{
bignum_data_t * userdata = (bignum_data_t *) luaL_checkudata(L, 1, "BIGNUM");
unsigned char * result = (unsigned char *) malloc( BN_num_bytes( userdata->bn ) );
if (!result) return luaL_error( L, "Couldn't allocate memory.");
int len = BN_bn2bin( userdata->bn, result );
lua_pushlstring( L, (char *) result, len );
free( result );
return 1;
}
static int l_bignum_bn2dec( lua_State *L ) /** bignum_bn2dec( BIGNUM bn ) */
{
bignum_data_t * userdata = (bignum_data_t *) luaL_checkudata(L, 1, "BIGNUM");
char * result = BN_bn2dec( userdata->bn );
lua_pushstring( L, result );
OPENSSL_free( result );
return 1;
}
static int l_bignum_bn2hex( lua_State *L ) /** bignum_bn2hex( BIGNUM bn ) */
{
bignum_data_t * userdata = (bignum_data_t *) luaL_checkudata(L, 1, "BIGNUM");
char * result = BN_bn2hex( userdata->bn );
lua_pushstring( L, result );
OPENSSL_free( result );
return 1;
}
static int l_bignum_free( lua_State *L ) /** bignum_free( bignum ) */
{
bignum_data_t * userdata = (bignum_data_t *) luaL_checkudata(L, 1, "BIGNUM");
BN_clear_free( userdata->bn );
return 0;
}
static int l_rand_bytes( lua_State *L ) /** rand_bytes( number bytes ) */
{
size_t len = luaL_checkint( L, 1 );
unsigned char * result = (unsigned char *) malloc( len );
if (!result) return luaL_error( L, "Couldn't allocate memory.");
RAND_bytes( result, len );
lua_pushlstring( L, (char *) result, len );
free( result );
return 1;
}
static int l_rand_pseudo_bytes( lua_State *L ) /** rand_pseudo_bytes( number bytes ) */
{
size_t len = luaL_checkint( L, 1 );
unsigned char * result = (unsigned char *) malloc( len );
if (!result) return luaL_error( L, "Couldn't allocate memory.");
RAND_pseudo_bytes( result, len );
lua_pushlstring( L, (char *) result, len );
free( result );
return 1;
}
static int l_md2(lua_State *L) /** md2(string s) */
{
size_t len;
const unsigned char *s = (unsigned char *) luaL_checklstring( L, 1, &len );
unsigned char digest[16];
lua_pushlstring( L, (char *) MD2( s, len, digest ), 16 );
return 1;
}
static int l_md4(lua_State *L) /** md4(string s) */
{
size_t len;
const unsigned char *s = (unsigned char *) luaL_checklstring( L, 1, &len );
unsigned char digest[16];
lua_pushlstring( L, (char *) MD4( s, len, digest ), 16 );
return 1;
}
static int l_md5(lua_State *L) /** md5(string s) */
{
size_t len;
const unsigned char *s = (unsigned char *) luaL_checklstring( L, 1, &len );
unsigned char digest[16];
lua_pushlstring( L, (char *) MD5( s, len, digest ), 16 );
return 1;
}
static int l_sha1(lua_State *L) /** sha1(string s) */
{
size_t len;
const unsigned char *s = (unsigned char *) luaL_checklstring( L, 1, &len );
unsigned char digest[20];
lua_pushlstring( L, (char *) SHA1( s, len, digest ), 20 );
return 1;
}
static int l_ripemd160(lua_State *L) /** ripemd160(string s) */
{
size_t len;
const unsigned char *s = (unsigned char *) luaL_checklstring( L, 1, &len );
unsigned char digest[20];
lua_pushlstring( L, (char *) RIPEMD160( s, len, digest ), 20 );
return 1;
}
static int l_digest(lua_State *L) /** digest(string algorithm, string message) */
{
size_t msg_len;
unsigned int digest_len;
const char *algorithm = luaL_checkstring( L, 1 );
const unsigned char *msg = (unsigned char *) luaL_checklstring( L, 2, &msg_len );
unsigned char digest[EVP_MAX_MD_SIZE];
const EVP_MD * evp_md;
EVP_MD_CTX mdctx;
evp_md = EVP_get_digestbyname( algorithm );
if (!evp_md) return luaL_error( L, "Unknown digest algorithm: %s", algorithm );
EVP_MD_CTX_init(&mdctx);
if (!(
EVP_DigestInit_ex( &mdctx, evp_md, NULL ) &&
EVP_DigestUpdate( &mdctx, msg, msg_len ) &&
EVP_DigestFinal_ex( &mdctx, digest, &digest_len ))) {
EVP_MD_CTX_cleanup( &mdctx );
return luaL_error( L, "OpenSSL error" );
}
EVP_MD_CTX_cleanup( &mdctx );
lua_pushlstring( L, (char *) digest, digest_len );
return 1;
}
static int l_hmac(lua_State *L) /** hmac(string algorithm, string key, string message) */
{
size_t key_len, msg_len;
unsigned int digest_len;
const char *algorithm = luaL_checkstring( L, 1 );
const unsigned char *key = (unsigned char *) luaL_checklstring( L, 2, &key_len );
const unsigned char *msg = (unsigned char *) luaL_checklstring( L, 3, &msg_len );
unsigned char digest[EVP_MAX_MD_SIZE];
const EVP_MD * evp_md;
evp_md = EVP_get_digestbyname( algorithm );
if (!evp_md) return luaL_error( L, "Unknown digest algorithm: %s", algorithm );
HMAC( evp_md, key, key_len, msg, msg_len, digest, &digest_len );
lua_pushlstring( L, (char *) digest, digest_len );
return 1;
}
struct enumerator_data {
lua_State * L;
int index;
};
static void enumerate_algorithms( const OBJ_NAME * name, void * arg )
{
struct enumerator_data* data = (struct enumerator_data *) arg;
lua_pushstring( data->L, name->name );
lua_rawseti( data->L, -2, data->index );
data->index++;
}
static int l_supported_digests(lua_State *L) /** supported_digests() */
{
enumerator_data data;
data.L = L;
data.index = 1;
lua_newtable( L );
OBJ_NAME_do_all_sorted( OBJ_NAME_TYPE_MD_METH,enumerate_algorithms, &data );
return 1;
}
static int l_supported_ciphers(lua_State *L) /** supported_ciphers() */
{
enumerator_data data;
data.L = L;
data.index = 1;
lua_newtable( L );
OBJ_NAME_do_all_sorted( OBJ_NAME_TYPE_CIPHER_METH,enumerate_algorithms, &data );
return 1;
}
static int l_encrypt(lua_State *L) /** encrypt( string algorithm, string key, string iv, string data, bool padding = false ) */
{
const char *algorithm = luaL_checkstring( L, 1 );
const EVP_CIPHER * evp_cipher = EVP_get_cipherbyname( algorithm );
if (!evp_cipher) return luaL_error( L, "Unknown cipher algorithm: %s", algorithm );
size_t data_len;
const unsigned char *key = (unsigned char *) luaL_checkstring( L, 2 );
const unsigned char *iv = (unsigned char *) luaL_optstring( L, 3, "" );
const unsigned char *data = (unsigned char *) luaL_checklstring( L, 4, &data_len );
int padding = lua_toboolean( L, 5 );
EVP_CIPHER_CTX cipher_ctx;
EVP_CIPHER_CTX_init( &cipher_ctx );
int out_len, final_len;
unsigned char * out = (unsigned char *) malloc( data_len + EVP_MAX_BLOCK_LENGTH );
if (!out) return luaL_error( L, "Couldn't allocate memory.");
if (!(
EVP_EncryptInit_ex( &cipher_ctx, evp_cipher, NULL, key, *iv ? iv : NULL ) &&
EVP_CIPHER_CTX_set_padding( &cipher_ctx, padding ) &&
EVP_EncryptUpdate( &cipher_ctx, out, &out_len, data, data_len ) &&
EVP_EncryptFinal_ex( &cipher_ctx, out + out_len, &final_len ) )) {
EVP_CIPHER_CTX_cleanup( &cipher_ctx );
free( out );
return luaL_error( L, "OpenSSL error" );
}
lua_pushlstring( L, (char *) out, out_len + final_len );
EVP_CIPHER_CTX_cleanup( &cipher_ctx );
free( out );
return 1;
}
static int l_decrypt(lua_State *L) /** decrypt( string algorithm, string key, string iv, string data, bool padding = false ) */
{
const char *algorithm = luaL_checkstring( L, 1 );
const EVP_CIPHER * evp_cipher = EVP_get_cipherbyname( algorithm );
if (!evp_cipher) return luaL_error( L, "Unknown cipher algorithm: %s", algorithm );
size_t data_len;
const unsigned char *key = (unsigned char *) luaL_checkstring( L, 2 );
const unsigned char *iv = (unsigned char *) luaL_optstring( L, 3, "" );
const unsigned char *data = (unsigned char *) luaL_checklstring( L, 4, &data_len );
int padding = lua_toboolean( L, 5 );
EVP_CIPHER_CTX cipher_ctx;
EVP_CIPHER_CTX_init( &cipher_ctx );
int out_len, final_len;
unsigned char * out = (unsigned char *) malloc( data_len );
if (!out) return luaL_error( L, "Couldn't allocate memory.");
if (!(
EVP_DecryptInit_ex( &cipher_ctx, evp_cipher, NULL, key, *iv ? iv : NULL ) &&
EVP_CIPHER_CTX_set_padding( &cipher_ctx, padding ) &&
EVP_DecryptUpdate( &cipher_ctx, out, &out_len, data, data_len ) &&
EVP_DecryptFinal_ex( &cipher_ctx, out + out_len, &final_len ) )) {
EVP_CIPHER_CTX_cleanup( &cipher_ctx );
free( out );
return luaL_error( L, "OpenSSL error" );
}
lua_pushlstring( L, (char *) out, out_len + final_len );
EVP_CIPHER_CTX_cleanup( &cipher_ctx );
free( out );
return 1;
}
static int l_DES_string_to_key(lua_State *L) /** DES_string_to_key( string data ) */
{
size_t len;
const unsigned char *data = (unsigned char *) luaL_checklstring( L, 1, &len );
if ( len != 7 )
return luaL_error( L, "String must have length of 7 bytes." );
DES_cblock key;
key[0] = data[0];
for( int i = 1; i < 8; i++ )
key[i] = data[i-1] << (8-i) | data[i] >> i;
DES_set_odd_parity( &key );
lua_pushlstring( L, (char *) key, 8 );
return 1;
}
static const struct luaL_reg bignum_methods[] = {
{ "num_bits", l_bignum_num_bits },
{ "num_bytes", l_bignum_num_bytes },
{ "tobin", l_bignum_bn2bin },
{ "todec", l_bignum_bn2dec },
{ "tohex", l_bignum_bn2hex },
{ "is_bit_set", l_bignum_is_bit_set },
{ "set_bit", l_bignum_set_bit },
{ "clear_bit", l_bignum_clear_bit },
{ "is_bit_set", l_bignum_is_bit_set },
{ "set_negative", l_bignum_set_negative },
{ "is_negative", l_bignum_is_negative },
{ "__gc", l_bignum_free },
{ NULL, NULL }
};
static const struct luaL_reg openssllib[] = {
{ "bignum_num_bits", l_bignum_num_bits },
{ "bignum_num_bytes", l_bignum_num_bytes },
{ "bignum_set_bit", l_bignum_set_bit },
{ "bignum_clear_bit", l_bignum_clear_bit },
{ "bignum_is_bit_set", l_bignum_is_bit_set },
{ "bignum_set_negative", l_bignum_set_negative },
{ "bignum_is_negative", l_bignum_is_negative },
{ "bignum_bin2bn", l_bignum_bin2bn },
{ "bignum_dec2bn", l_bignum_dec2bn },
{ "bignum_hex2bn", l_bignum_hex2bn },
{ "bignum_rand", l_bignum_rand },
{ "bignum_pseudo_rand", l_bignum_pseudo_rand },
{ "bignum_bn2bin", l_bignum_bn2bin },
{ "bignum_bn2dec", l_bignum_bn2dec },
{ "bignum_bn2hex", l_bignum_bn2hex },
{ "bignum_mod_exp", l_bignum_mod_exp },
{ "rand_bytes", l_rand_bytes },
{ "rand_pseudo_bytes", l_rand_pseudo_bytes },
{ "md2", l_md2 },
{ "md4", l_md4 },
{ "md5", l_md5 },
{ "sha1", l_sha1 },
{ "ripemd160", l_ripemd160 },
{ "digest", l_digest },
{ "hmac", l_hmac },
{ "encrypt", l_encrypt },
{ "decrypt", l_decrypt },
{ "DES_string_to_key", l_DES_string_to_key },
{ "supported_digests", l_supported_digests },
{ "supported_ciphers", l_supported_ciphers },
{ NULL, NULL }
};
LUALIB_API int luaopen_openssl(lua_State *L) {
OpenSSL_add_all_algorithms();
luaL_register(L, OPENSSLLIBNAME, openssllib);
// create metatable for bignum
luaL_newmetatable( L, "BIGNUM" );
// metatable.__index = metatable
lua_pushvalue( L, -1 );
lua_setfield( L, -2, "__index" );
// register methods
luaL_register( L, NULL, bignum_methods );
lua_pop( L, 1 ); // BIGNUM
return 1;
}

19
nse_openssl.h Normal file
View File

@@ -0,0 +1,19 @@
#include "../nmap_config.h"
#if HAVE_OPENSSL
#ifndef OPENSSLLIB
#define OPENSSLLIB
#define OPENSSLLIBNAME "openssl"
extern "C" {
#include "lua.h"
#include "lauxlib.h"
}
LUALIB_API int luaopen_openssl(lua_State *L);
#endif
#endif

View File

@@ -3,15 +3,24 @@
module(... or "pop3",package.seeall) module(... or "pop3",package.seeall)
local HAVE_SSL = false
require 'base64' require 'base64'
require 'bit' require 'bit'
require 'stdnse'
if pcall(require,'openssl') then
HAVE_SSL = true
end
err = { err = {
none = 0, none = 0,
userError = 1, userError = 1,
pwError = 2, pwError = 2,
informationMissing = 3 informationMissing = 3,
OpenSSLMissing = 4,
} }
--- ---
@@ -112,8 +121,8 @@ end
function login_apop(socket, user, pw, challenge) function login_apop(socket, user, pw, challenge)
if type(challenge) ~= "string" then return false, err.informationMissing end if type(challenge) ~= "string" then return false, err.informationMissing end
local apStr = hash.md5(challenge .. pw) local apStr = stdnse.tohex(openssl.md5(challenge .. pw))
socket:send("APOP " .. user .. " " .. apStr .. "\r\n") socket:send(("APOP %s %s\r\n"):format(user, apStr))
status, line = socket:receive_lines(1) status, line = socket:receive_lines(1)
@@ -168,33 +177,6 @@ function capabilities(host, port)
return capas return capas
end end
---
-- Calculate HMAC-MD5 hash
--@param key Key for hash calculation
--@param msg Message to be hashed
--@return HMAC-MD5 of given message
function hmacMD5(key, msg)
local ipad = {}
local opad = {}
if (string.len(key) > 64) then
key = hash.md5binary(key)
end
-- create both pads, XORing with key
for i = 1, string.len(key) do
ipad[i] = string.char(bit.bxor(0x36, string.byte(string.sub(key, i))))
opad[i] = string.char(bit.bxor(0x5c, string.byte(string.sub(key, i))))
end
for i = #ipad + 1, 64 do
ipad[i] = string.char(0x36)
opad[i] = string.char(0x5c)
end
-- calc HMAC-md5
return hash.md5(table.concat(opad) .. hash.md5bin(table.concat(ipad) .. msg))
end
--- ---
-- Try to login using AUTH command using SASL/CRAM-MD5 method -- Try to login using AUTH command using SASL/CRAM-MD5 method
--@param socket Socket connected to POP3 server --@param socket Socket connected to POP3 server
@@ -209,7 +191,7 @@ function login_sasl_crammd5(socket, user, pw)
local challenge = base64.dec(string.sub(line, 3)) local challenge = base64.dec(string.sub(line, 3))
local digest = hmacMD5(pw, challenge) local digest = stdnse.tohex(openssl.hmac('md5', pw, challenge))
local authStr = base64.enc(user .. " " .. digest) local authStr = base64.enc(user .. " " .. digest)
socket:send(authStr .. "\r\n") socket:send(authStr .. "\r\n")
@@ -221,3 +203,15 @@ function login_sasl_crammd5(socket, user, pw)
return false, err.pwError return false, err.pwError
end end
end end
--- overwrite functions requiring OpenSSL if we got no OpenSSL
if not HAVE_SSL then
local no_ssl = function()
return false, err.OpenSSLMissing
end
login_apop = no_ssl
login_sasl_crammd5 = no_ssl
end

152
nselib/ssh1.lua Normal file
View File

@@ -0,0 +1,152 @@
-- @author = Sven Klemm <sven@c3d2.de>
-- @copyright See nmaps COPYING for licence
module(... or "ssh1",package.seeall)
local bin = require "bin"
local bit = require "bit"
local math = require "math"
local stdnse = require "stdnse"
local openssl = require "openssl"
--- fetch SSH1 host key
--@param host nmap host table
--@param port nmap port table
fetch_host_key = function(host, port)
local socket = nmap.new_socket()
local catch = function() socket:close() end
local try = nmap.new_try(catch)
try(socket:connect(host.ip, port.number))
-- fetch banner
try(socket:receive_lines(1))
-- send our banner
try(socket:send("SSH-1.5-Nmap-SSH1-Hostkey\r\n"))
local data, packet_length, padding, offset
data = try(socket:receive())
socket:close()
offset, packet_length = bin.unpack( ">i", data )
padding = 8 - packet_length % 8
offset = offset + padding
if padding + packet_length + 4 == data:len() then
-- seems to be a proper SSH1 packet
local msg_code,host_key_bits,exp,mod,length,fp_input
offset, msg_code = bin.unpack( ">c", data, offset )
if msg_code == 2 then -- 2 => SSH_SMSG_PUBLIC_KEY
-- ignore cookie and server key bits
offset, _, _ = bin.unpack( ">A8i", data, offset )
-- skip server key exponent and modulus
offset, length = bin.unpack( ">S", data, offset )
offset = offset + math.ceil( length / 8 )
offset, length = bin.unpack( ">S", data, offset )
offset = offset + math.ceil( length / 8 )
offset, host_key_bits = bin.unpack( ">i", data, offset )
offset, length = bin.unpack( ">S", data, offset )
offset, exp = bin.unpack( ">A" .. math.ceil( length / 8 ), data, offset )
exp = openssl.bignum_bin2bn( exp )
offset, length = bin.unpack( ">S", data, offset )
offset, mod = bin.unpack( ">A" .. math.ceil( length / 8 ), data, offset )
mod = openssl.bignum_bin2bn( mod )
fp_input = mod:tobin()..exp:tobin()
return {exp=exp,mod=mod,bits=host_key_bits,key_type='rsa1',fp_input=fp_input,
full_key=exp:todec()..' '..mod:todec(),algorithm="RSA1",
fingerprint=openssl.md5(fp_input)}
end
end
end
--- format key as hexadecimal fingerprint
fingerprint_hex = function( fingerprint, algorithm, bits )
fingerprint = stdnse.tohex(fingerprint,{separator=":",group=2})
return ("%d %s (%s)"):format( bits, fingerprint, algorithm )
end
--- format key as bubblebabble fingerprint
fingerprint_bubblebabble = function( fingerprint, algorithm, bits )
local vowels = {'a','e','i','o','u','y'}
local consonants = {'b','c','d','f','g','h','k','l','m','n','p','r','s','t','v','z','x'}
local s = "x"
local seed = 1
for i=1,#fingerprint+2,2 do
local in1,in2,idx1,idx2,idx3,idx4,idx5
if i < #fingerprint or #fingerprint / 2 % 2 ~= 0 then
in1 = fingerprint:byte(i)
idx1 = (bit.band(bit.rshift(in1,6),3) + seed) % 6 + 1
idx2 = bit.band(bit.rshift(in1,2),15) + 1
idx3 = (bit.band(in1,3) + math.floor(seed/6)) % 6 + 1
s = s .. vowels[idx1] .. consonants[idx2] .. vowels[idx3]
if i < #fingerprint then
in2 = fingerprint:byte(i+1)
idx4 = bit.band(bit.rshift(in2,4),15) + 1
idx5 = bit.band(in2,15) + 1
s = s .. consonants[idx4] .. '-' .. consonants[idx5]
seed = (seed * 5 + in1 * 7 + in2) % 36
end
else
idx1 = seed % 6 + 1
idx2 = 16 + 1
idx3 = math.floor(seed/6) + 1
s = s .. vowels[idx1] .. consonants[idx2] .. vowels[idx3]
end
end
s = s .. 'x'
return ("%d %s (%s)"):format( bits, s, algorithm )
end
--- format key as visual fingerprint
-- ported from http://www.openbsd.org/cgi-bin/cvsweb/~checkout~/src/usr.bin/ssh/key.c
fingerprint_visual = function( fingerprint, algorithm, bits )
local i,j,field,characters,input,fieldsize_x,fieldsize_y,s
fieldsize_x, fieldsize_y = 17, 9
characters = {' ','.','o','+','=','*','B','O','X','@','%','&','#','/','^','S','E'}
-- initialize drawing area
field = {}
for i=1,fieldsize_x do
field[i]={}
for j=1,fieldsize_y do field[i][j]=1 end
end
-- we start in the center and mark it
x, y = math.ceil(fieldsize_x/2), math.ceil(fieldsize_y/2)
field[x][y] = #characters - 1;
-- iterate over fingerprint
for i=1,#fingerprint do
input = fingerprint:byte(i)
-- each byte conveys four 2-bit move commands
for j=1,4 do
if bit.band( input, 1) == 1 then x = x + 1 else x = x - 1 end
if bit.band( input, 2) == 2 then y = y + 1 else y = y - 1 end
x = math.max(x,1); x = math.min(x,fieldsize_x)
y = math.max(y,1); y = math.min(y,fieldsize_y)
if field[x][y] < #characters - 2 then
field[x][y] = field[x][y] + 1
end
input = bit.rshift( input, 2 )
end
end
-- mark end point
field[x][y] = #characters;
-- build output
s = ('\n+--[%4s %4d]----+\n'):format( algorithm, bits )
for i=1,fieldsize_y do
s = s .. '|'
for j=1,fieldsize_x do s = s .. characters[ field[j][i] ] end
s = s .. '|\n'
end
s = s .. '+-----------------+\n'
return s
end

187
nselib/ssh2.lua Normal file
View File

@@ -0,0 +1,187 @@
-- @author = Sven Klemm <sven@c3d2.de>
-- @copyright See nmaps COPYING for licence
module(... or "ssh2",package.seeall)
require "bin"
require "base64"
require "openssl"
require "stdnse"
-- table holding transport layer functions
transport = {}
-- table of SSH2 constants
local SSH2
--- pack multiprecision integer for sending
--@param bn openssl bignum
--@return packed multiprecision integer
transport.pack_mpint = function( bn )
local bytes, packed
bytes = bn:num_bytes()
packed = bn:tobin()
if bytes % 8 == 0 then
bytes = bytes + 1
packed = string.char(0) .. packed
end
return bin.pack( ">IA", bytes, packed )
end
--- build a ssh2 packet
--@param payload payload of the packet
--@return packet to send on the wire
transport.build = function( payload )
local packet_length, padding_length
padding_length = 8 - ( (payload:len() + 1 + 4 ) % 8 )
packet_length = payload:len() + padding_length + 1
return bin.pack( ">IcAA", packet_length, padding_length, payload, openssl.rand_pseudo_bytes( padding_length ) )
end
--- extract the payload from a received SSH2 packet
--@param received SSH2 packet
--@return payload of the SSH2 packet
transport.payload = function( packet )
local packet_length, padding_length, payload_length, payload, offset
offset, packet_length, padding_length = bin.unpack( ">Ic", packet )
payload_length = packet_length - padding_length - 1
offset, payload = bin.unpack( ">A" .. payload_length, packet, offset )
return payload
end
--- build kexdh_init packet
transport.kexdh_init = function( e )
return bin.pack( ">cA", SSH2.SSH_MSG_KEXDH_INIT, transport.pack_mpint( e ) )
end
--- build kex_init packet
transport.kex_init = function( cookie, options )
options = options or {}
kex_algorithms = "diffie-hellman-group1-sha1"
host_key_algorithms = options['host_key_algorithms'] or "ssh-dss,ssh-rsa"
encryption_algorithms = "aes128-cbc,3des-cbc,blowfish-cbc,aes192-cbc,aes256-cbc,aes128-ctr,aes192-ctr,aes256-ctr"
mac_algorithms = "hmac-md5,hmac-sha1,hmac-ripemd160"
compression_algorithms = "none"
languages = ""
local payload = bin.pack( ">cAaa", SSH2.SSH_MSG_KEXINIT, cookie, kex_algorithms, host_key_algorithms )
payload = payload .. bin.pack( ">aa", encryption_algorithms, encryption_algorithms )
payload = payload .. bin.pack( ">aa", mac_algorithms, mac_algorithms )
payload = payload .. bin.pack( ">aa", compression_algorithms, compression_algorithms )
payload = payload .. bin.pack( ">aa", languages, languages )
payload = payload .. bin.pack( ">cI", 0, 0 )
return payload
end
--- parse kexinit package
-- returns an empty table in case of an error
transport.parse_kex_init = function( payload )
local _, offset, msg_code, parsed, fields, fieldname
parsed = {}
-- check for proper msg code
offset, msg_code = bin.unpack( ">c", payload )
if msg_code ~= SSH2.SSH_MSG_KEXINIT then return {} end
offset, parsed.cookie = bin.unpack( ">A16", payload, offset )
fields = {'kex_algorithms','server_host_key_algorithms',
'encryption_algorithms_client_to_server','encryption_algorithms_server_to_client',
'mac_algorithms_client_to_server','mac_algorithms_server_to_client',
'compression_algorithms_client_to_server','compression_algorithms_server_to_client',
'languages_client_to_server','languages_server_to_client'}
for _, fieldname in pairs( fields ) do
offset, parsed[fieldname] = bin.unpack( ">a", payload, offset )
end
return parsed
end
--- fetch SSH2 host key
--@param host nmap host table
--@param port nmap port table
--@param key_type key type to fetch
--@return table containing the key and fingerprint
fetch_host_key = function( host, port, key_type )
local socket = nmap.new_socket()
local catch = function() socket:close() end
local try = nmap.new_try(catch)
-- oakley group 2 prime taken from rfc 2409
local prime = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF"
try(socket:connect(host.ip, port.number))
-- fetch banner
try(socket:receive_lines(1))
-- send our banner
try(socket:send("SSH-2.0-Nmap-SSH2-Hostkey\r\n"))
local cookie = openssl.rand_bytes( 16 )
local packet = transport.build( transport.kex_init( cookie, {host_key_algorithms=key_type} ) )
try(socket:send( packet ))
local kex_init = try(socket:receive_bytes(1))
kex_init = transport.parse_kex_init( transport.payload( kex_init ) )
if not tostring(kex_init.server_host_key_algorithms):find( key_type, 1, true ) then
-- server does not support host key type
stdnse.print_debug( 2, "Hostkey type '%s' not supported by server.", key_type )
return
end
local e, g, x, p
-- e = g^x mod p
g = openssl.bignum_dec2bn( "2" )
p = openssl.bignum_hex2bn( prime )
x = openssl.bignum_pseudo_rand( 1024 )
e = openssl.bignum_mod_exp( g, x, p )
packet = transport.build( transport.kexdh_init( e ) )
try(socket:send( packet ))
kexdh_reply = try(socket:receive_bytes(1))
kexdh_reply = transport.payload( kexdh_reply )
-- check for proper msg code
if kexdh_reply:byte(1) ~= SSH2.SSH_MSG_KEXDH_REPLY then
return
end
local _,public_host_key,bits,algorithm
_, _, public_host_key = bin.unpack( ">ca", kexdh_reply )
if key_type == 'ssh-dss' then
algorithm = "DSA"
local p
_, _, p = bin.unpack( ">aa", public_host_key )
bits = openssl.bignum_bin2bn( p ):num_bits()
elseif key_type == 'ssh-rsa' then
algorithm = "RSA"
local n
_, _, _, n = bin.unpack( ">aaa", public_host_key )
bits = openssl.bignum_bin2bn( n ):num_bits()
else
stdnse.print_debug( "Unsupported key type: %s", key_type )
end
return { key=public_host_key, key_type=key_type, fp_input=public_host_key, bits=bits,
full_key=('%s %s'):format(key_type,base64.enc(public_host_key)),
algorithm=algorithm, fingerprint=openssl.md5(public_host_key) }
end
-- constants
SSH2 = {
SSH_MSG_DISCONNECT = 1,
SSH_MSG_IGNORE = 2,
SSH_MSG_UNIMPLEMENTED = 3,
SSH_MSG_DEBUG = 4,
SSH_MSG_SERVICE_REQUEST = 5,
SSH_MSG_SERVICE_ACCEPT = 6,
SSH_MSG_KEXINIT = 20,
SSH_MSG_NEWKEYS = 21,
SSH_MSG_KEXDH_INIT = 30,
SSH_MSG_KEXDH_REPLY = 31,
}

103
scripts/SSH-hostkey.nse Normal file
View File

@@ -0,0 +1,103 @@
--- Shows SSH Hostkeys
--
-- Shows fingerprint or fingerprint and key depending on verbosity level.
-- Puts the found hostkeys in nmap.registry for other scripts to use them.
-- You can control the output with the ssh_hostkey script argument. Possible
-- values are bubble,visual,full and all.
--
--@usage
-- nmap host --script SSH-hostkey --script-args ssh_hostkey=full
-- nmap host --script SSH-hostkey --script-args ssh_hostkey=all
-- nmap host --script SSH-hostkey --script-args ssh_hostkey='visual bubble'
--
--@output
-- 22/tcp open ssh
-- | SSH Hostkey: 2048 f0:58:ce:f4:aa:a4:59:1c:8e:dd:4d:07:44:c8:25:11 (RSA)
-- 22/tcp open ssh
-- | SSH Hostkey: 2048 f0:58:ce:f4:aa:a4:59:1c:8e:dd:4d:07:44:c8:25:11 (RSA)
-- | +--[ RSA 2048]----+
-- | | .E*+ |
-- | | oo |
-- | | . o . |
-- | | O . . |
-- | | o S o . |
-- | | = o + . |
-- | | . * o . |
-- | | = . |
-- | | o . |
-- |_ +-----------------+
-- 22/tcp open ssh
-- | SSH Hostkey: 2048 xuvah-degyp-nabus-zegah-hebur-nopig-bubig-difeg-hisym-rumef-cuxex (RSA)
-- |_ ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAwVuv2gcr0maaKQ69VVIEv2ob4OxnuI64fkeOnCXD1lUx5tTA+vefXUWEMxgMuA7iX4irJHy2zer0NQ3Z3yJvr5scPgTYIaEOp5Uo/eGFG9Agpk5wE8CoF0e47iCAPHqzlmP2V7aNURLMODb3jVZuI07A2ZRrMGrD8d888E2ORVORv1rYeTYCqcMMoVFmX9l3gWEdk4yx3w5sD8v501Iuyd1v19mPfyhrI5E1E1nl/Xjp5N0/xP2GUBrdkDMxKaxqTPMie/f0dXBUPQQN697a5q+5lBRPhKYOtn6yQKCd9s1Q22nxn72Jmi1RzbMyYJ52FosDT755Qmb46GLrDMaZMQ==
id = "SSH Hostkey"
author = "Sven Klemm <sven@c3d2.de>"
description = "Show SSH Hostkeys"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"safe","default","intrusive"}
require("shortport")
require("stdnse")
-- openssl is required for this script
if pcall(require,"openssl") then
require("ssh1")
require("ssh2")
else
action = function()
stdnse.print_debug( 3, "Skipping %s script because OpenSSL is missing.", id )
end
end
portrule = shortport.port_or_service(22, "ssh")
--- put hostkey in the nmap registry for usage by other scripts
--@param host nmap host table
--@param key host key table
local add_key_to_registry = function( host, key )
nmap.registry[id] = nmap.registry[id] or {}
nmap.registry[id][host.ip] = nmap.registry[id][host.ip] or {}
table.insert( nmap.registry[id][host.ip], key )
end
action = action or function(host, port)
local output = {}
local keys = {}
local _,key
local format = nmap.registry.args.ssh_hostkey or "hex"
local all_formats = format:find( 'all', 1, true )
key = ssh1.fetch_host_key( host, port )
if key then table.insert( keys, key ) end
key = ssh2.fetch_host_key( host, port, "ssh-dss" )
if key then table.insert( keys, key ) end
key = ssh2.fetch_host_key( host, port, "ssh-rsa" )
if key then table.insert( keys, key ) end
for _, key in ipairs( keys ) do
add_key_to_registry( host, key )
if format:find( 'hex', 1, true ) or all_formats then
table.insert( output, ssh1.fingerprint_hex( key.fingerprint, key.algorithm, key.bits ) )
end
if format:find( 'bubble', 1, true ) or all_formats then
table.insert( output, ssh1.fingerprint_bubblebabble( openssl.sha1(key.fp_input), key.algorithm, key.bits ) )
end
if format:find( 'visual', 1, true ) or all_formats then
-- insert empty line so table is not destroyed if this is the first
-- line of output
if #output == 0 then table.insert( output, " " ) end
table.insert( output, ssh1.fingerprint_visual( key.fingerprint, key.algorithm, key.bits ) )
end
if nmap.verbosity() > 1 or format:find( 'full', 1, true ) or all_formats then
table.insert( output, key.full_key )
end
end
if #output > 0 then
return table.concat( output, '\n' )
end
end