Index: Makefile.in =================================================================== --- Makefile.in (revision 33536) +++ Makefile.in (working copy) @@ -25,8 +25,8 @@ export NCATDIR=@NCATDIR@ CC = @CC@ CXX = @CXX@ -CCOPT = -DBGFLAGS = +CCOPT = +DBGFLAGS = STRIP = @STRIP@ LIBPCAPDIR = @libpcapdir@ LIBPCREDIR = @LIBPCREDIR@ @@ -50,7 +50,7 @@ # CFLAGS = $(DEFS) $(INCLS) STATIC = LDFLAGS = @LDFLAGS@ $(DBGFLAGS) $(STATIC) -LIBS = @LIBNBASE_LIBS@ @LIBNSOCK_LIBS@ @LIBPCRE_LIBS@ @LIBPCAP_LIBS@ $(OPENSSL_LIBS) libnetutil/libnetutil.a @LIBDNET_LIBS@ @LIBLUA_LIBS@ @LIBLINEAR_LIBS@ @LIBSSH2_LIBS@ @LIBS@ +LIBS = @LIBNBASE_LIBS@ @LIBNSOCK_LIBS@ @LIBPCRE_LIBS@ @LIBPCAP_LIBS@ $(OPENSSL_LIBS) libnetutil/libnetutil.a @LIBDNET_LIBS@ @LIBLUA_LIBS@ @LIBLINEAR_LIBS@ @LIBZLIB_LIBS@ @LIBSSH2_LIBS@ @LIBS@ OPENSSL_LIBS = @OPENSSL_LIBS@ # LIBS = -lefence @LIBS@ # LIBS = -lrmalloc @LIBS@ @@ -70,7 +70,7 @@ # DESTDIR is used by some package maintainers to install Nmap under -# its usual directory structure into a different tree. See the +# its usual directory structure into a different tree. See the # CHANGELOG for more info. DESTDIR = @@ -99,8 +99,14 @@ NSE_HDRS+=nse_openssl.h nse_ssl_cert.h NSE_OBJS+=nse_openssl.o nse_ssl_cert.o endif +ifneq (@LIBZLIB_LIBS@,) +NSE_SRC+=nse_zlib.cc +NSE_HDRS+=nse_zlib.h +NSE_OBJS+=nse_zlib.o endif +endif + export SRCS = charpool.cc FingerPrintResults.cc FPEngine.cc FPModel.cc idle_scan.cc MACLookup.cc main.cc nmap.cc nmap_dns.cc nmap_error.cc nmap_ftp.cc NmapOps.cc NmapOutputTable.cc nmap_tty.cc osscan2.cc osscan.cc output.cc payload.cc portlist.cc portreasons.cc protocols.cc scan_engine.cc service_scan.cc services.cc Target.cc TargetGroup.cc targets.cc tcpip.cc timing.cc traceroute.cc utils.cc xml.cc $(NSE_SRC) export HDRS = charpool.h FingerPrintResults.h FPEngine.h global_structures.h idle_scan.h MACLookup.h nmap_amigaos.h nmap_dns.h nmap_error.h nmap.h nmap_ftp.h NmapOps.h NmapOutputTable.h nmap_tty.h nmap_winconfig.h osscan2.h osscan.h output.h payload.h portlist.h portreasons.h protocols.h scan_engine.h service_scan.h services.h TargetGroup.h Target.h targets.h tcpip.h timing.h traceroute.h utils.h xml.h $(NSE_HDRS) @@ -410,7 +416,7 @@ check: @NCAT_CHECK@ @NSOCK_CHECK@ @ZENMAP_CHECK@ @NSE_CHECK@ @NDIFF_CHECK@ -${srcdir}/configure: configure.ac +${srcdir}/configure: configure.ac cd ${srcdir} && autoconf ## autoheader might not change config.h.in, so touch a stamp file. Index: configure =================================================================== --- configure (revision 33536) +++ configure (working copy) @@ -662,6 +662,7 @@ LIBDNETDIR LIBDNET_LIBS LIBSSH2_LIBS +LIBZLIB_LIBS PCRE_DIST_CLEAN PCRE_CLEAN PCRE_BUILD @@ -782,6 +783,7 @@ with_openssl with_libpcap with_libpcre +with_zlib with_libssh2 with_libdnet with_liblua @@ -1441,6 +1443,7 @@ --with-libpcre=DIR Use an existing (compiled) pcre lib from DIR/include and DIR/lib. --with-libpcre=included Always use the version included with Nmap + --with-zlib=DIR Use the zlib library from DIR/lib and DIR/include. --with-libssh2=DIR Use speficic copy of libssh2 --with-libdnet=DIR Use an existing (compiled) dnet lib from DIR/include and DIR/lib. This is NOT RECOMMENDED because we have @@ -6741,6 +6744,94 @@ +# zlib +have_zlib=no + +# Check whether --with-zlib was given. +if test "${with_zlib+set}" = set; then : + withval=$with_zlib; case "$with_zlib" in + yes) + have_zlib=yes + ;; + included) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \"zlib is not included with Nmap. Will try to find system version\"" >&5 +$as_echo "$as_me: WARNING: \"zlib is not included with Nmap. Will try to find system version\"" >&2;} + ;; + *) + have_zlib=yes + CPPFLAGS="-I$with_zlib/include $CPPFLAGS" + LDFLAGS="-L$with_zlib/lib $LDFLAGS" + ;; + esac + +fi + + +if test $have_zlib != yes; then + for ac_header in zlib.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default" +if test "x$ac_cv_header_zlib_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ZLIB_H 1 +_ACEOF + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gzread in -lz" >&5 +$as_echo_n "checking for gzread in -lz... " >&6; } +if ${ac_cv_lib_z_gzread+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lz $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char gzread (); +int +main () +{ +return gzread (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_z_gzread=yes +else + ac_cv_lib_z_gzread=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_gzread" >&5 +$as_echo "$ac_cv_lib_z_gzread" >&6; } +if test "x$ac_cv_lib_z_gzread" = xyes; then : + have_zlib=yes; break +fi + +fi + +done + +fi + +LIBZLIB_LIBS= +if test $have_zlib = yes; then + LIBZLIB_LIBS="-lz" + $as_echo "#define HAVE_ZLIB 1" >>confdefs.h + +fi + + + + + have_libssh2=no # Check whether --with-libssh2 was given. Index: configure.ac =================================================================== --- configure.ac (revision 33536) +++ configure.ac (working copy) @@ -510,6 +510,40 @@ AC_SUBST(PCRE_DIST_CLEAN) +# zlib +have_zlib=no +AC_ARG_WITH(zlib, +AC_HELP_STRING([--with-zlib=DIR], [Use the zlib library from DIR/lib and DIR/include.]), +[ case "$with_zlib" in + yes) + have_zlib=yes + ;; + included) + AC_MSG_WARN("zlib is not included with Nmap. Will try to find system version") + ;; + *) + have_zlib=yes + CPPFLAGS="-I$with_zlib/include $CPPFLAGS" + LDFLAGS="-L$with_zlib/lib $LDFLAGS" + ;; + esac] +) + +if test $have_zlib != yes; then + AC_CHECK_HEADERS([zlib.h], + AC_CHECK_LIB(z, gzread, [have_zlib=yes; break],, [])) +fi + +LIBZLIB_LIBS= +if test $have_zlib = yes; then + LIBZLIB_LIBS="-lz" + AC_DEFINE(HAVE_ZLIB) +fi +AC_SUBST(LIBZLIB_LIBS) + + + + have_libssh2=no AC_ARG_WITH(libssh2, AC_HELP_STRING([--with-libssh2=DIR], [Use speficic copy of libssh2]), Index: nse_main.cc =================================================================== --- nse_main.cc (revision 33536) +++ nse_main.cc (working copy) @@ -20,6 +20,7 @@ #include "nse_openssl.h" #include "nse_debug.h" #include "nse_lpeg.h" +#include "nse_zlib.h" #include "nse_libssh2.h" #define NSE_MAIN "NSE_MAIN" /* the main function */ @@ -552,6 +553,9 @@ #ifdef HAVE_OPENSSL {OPENSSLLIBNAME, luaopen_openssl}, #endif +#ifdef HAVE_ZLIB + {NSE_ZLIBNAME, luaopen_zlib}, +#endif {NULL, NULL} }; Index: nse_zlib.cc =================================================================== --- nse_zlib.cc (revision 0) +++ nse_zlib.cc (working copy) @@ -0,0 +1,924 @@ +/************************************************************************ +* Author : Tiago Dionizio * +* Library : lzlib - Lua 5 interface to access zlib library functions * +* * +* 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. * +************************************************************************/ + +#include +#include + +extern "C" { + #include "lauxlib.h" + #include "lualib.h" + #include "lua.h" +} + +#include + +#define ZSTREAMMETA "zlib:zstream" + +#define LZ_ANY -1 +#define LZ_NONE 0 +#define LZ_DEFLATE 1 +#define LZ_INFLATE 2 + +#if 0 + #define LZ_BUFFER_SIZE LUAL_BUFFERSIZE +#else + #define LZ_BUFFER_SIZE 8192 +#endif + +typedef struct { + /* zlib structures */ + z_stream zstream; + /* stream state. LZ_DEFLATE | LZ_INFLATE */ + int state; + int error; + int peek; + int eos; + /* user callback source for reading/writing */ + int io_cb; + /* input buffer */ + int i_buffer_ref; + size_t i_buffer_pos; + size_t i_buffer_len; + const char *i_buffer; + /* output buffer */ + size_t o_buffer_len; + size_t o_buffer_max; + char o_buffer[LZ_BUFFER_SIZE]; + /* dictionary */ + const Bytef *dictionary; + size_t dictionary_len; +} lz_stream; + + +/* forward declarations */ +static int lzstream_docompress( + lua_State *L, lz_stream *s, int from, int to, int flush); + + +static lz_stream *lzstream_new(lua_State *L, int src) { + lz_stream *s = (lz_stream*)lua_newuserdata(L, sizeof(lz_stream)); + + luaL_getmetatable(L, ZSTREAMMETA); + lua_setmetatable(L, -2); /* set metatable */ + + s->state = LZ_NONE; + s->error = Z_OK; + s->eos = 0; + s->io_cb = LUA_REFNIL; + + s->i_buffer = NULL; + s->i_buffer_ref = LUA_REFNIL; + s->i_buffer_pos = 0; + s->i_buffer_len = 0; + + s->peek = 0; + s->o_buffer_len = 0; + s->o_buffer_max = sizeof(s->o_buffer) / sizeof(s->o_buffer[0]); + + s->zstream.zalloc = Z_NULL; + s->zstream.zfree = Z_NULL; + + /* prepare source */ + if (lua_isstring(L, src)) { + lua_pushvalue(L, src); + s->i_buffer_ref = luaL_ref(L, LUA_REGISTRYINDEX); + s->i_buffer = lua_tolstring(L, src, &s->i_buffer_len); + } else { + /* table | function | userdata */ + lua_pushvalue(L, src); + s->io_cb = luaL_ref(L, LUA_REGISTRYINDEX); + } + return s; +} + +static void lzstream_cleanup(lua_State *L, lz_stream *s) { + if (s && s->state != LZ_NONE) { + if (s->state == LZ_INFLATE) { + inflateEnd(&s->zstream); + } + if (s->state == LZ_DEFLATE) { + deflateEnd(&s->zstream); + } + + luaL_unref(L, LUA_REGISTRYINDEX, s->io_cb); + luaL_unref(L, LUA_REGISTRYINDEX, s->i_buffer_ref); + s->state = LZ_NONE; + } +} + +static lz_stream *lzstream_get(lua_State *L, int index) { + lz_stream *s = (lz_stream*)luaL_checkudata(L, index, ZSTREAMMETA); + if (s == NULL) luaL_argerror(L, index, "bad zlib stream"); + return s; +} + +static lz_stream *lzstream_check(lua_State *L, int index, int state) { + lz_stream *s = lzstream_get(L, index); + if ((state != LZ_ANY && s->state != state) || s->state == LZ_NONE) { + luaL_argerror(L, index, "attempt to use invalid zlib stream"); + } + return s; +} + +static int lzstream_tostring(lua_State *L) { + lz_stream *s = (lz_stream*)luaL_checkudata(L, 1, ZSTREAMMETA); + if (s == NULL) luaL_argerror(L, 1, "bad zlib stream"); + + if (s->state == LZ_NONE) { + lua_pushstring(L, "zlib stream (closed)"); + } else if (s->state == LZ_DEFLATE) { + lua_pushfstring(L, "zlib deflate stream (%p)", (void*)s); + } else if (s->state == LZ_INFLATE) { + lua_pushfstring(L, "zlib inflate stream (%p)", (void*)s); + } else { + lua_pushfstring(L, "%p", (void*)s); + } + + return 1; +} + +static int lzstream_gc(lua_State *L) { + lz_stream *s = lzstream_get(L, 1); + lzstream_cleanup(L, s); + return 0; +} + +static int lzstream_close(lua_State *L) { + lz_stream *s = lzstream_get(L, 1); + + if (s->state == LZ_DEFLATE) { + lua_settop(L, 0); + lua_pushliteral(L, ""); + return lzstream_docompress(L, s, 1, 1, Z_FINISH); + } + + lzstream_cleanup(L, s); + lua_pushboolean(L, 1); + return 1; +} + +static int lzstream_adler(lua_State *L) { + lz_stream *s = lzstream_check(L, 1, LZ_ANY); + lua_pushnumber(L, s->zstream.adler); + return 1; +} + +/* + zlib.deflate( + sink: function | { write: function [, close: function, flush: function] }, + compression level, [Z_DEFAILT_COMPRESSION] + method, [Z_DEFLATED] + windowBits, [15] + memLevel, [8] + strategy, [Z_DEFAULT_STRATEGY] + dictionary: [""] + ) +*/ +static int lzlib_deflate(lua_State *L) { + int level, method, windowBits, memLevel, strategy; + lz_stream *s; + const char *dictionary; + size_t dictionary_len; + + if (lua_istable(L, 1) || lua_isuserdata(L, 1)) { + /* is there a :write function? */ + lua_getfield(L, 1, "write"); + if (!lua_isfunction(L, -1)) { + luaL_argerror( + L, 1, "output does not provide :write function"); + } + lua_pop(L, 1); + } + else if (!lua_isfunction(L, 1)) { + luaL_argerror( + L, 1, "output must be a function, table or userdata value"); + } + + level = luaL_optint(L, 2, Z_DEFAULT_COMPRESSION); + method = luaL_optint(L, 3, Z_DEFLATED); + windowBits = luaL_optint(L, 4, 15); + memLevel = luaL_optint(L, 5, 8); + strategy = luaL_optint(L, 6, Z_DEFAULT_STRATEGY); + dictionary = luaL_optlstring(L, 7, NULL, &dictionary_len); + + s = lzstream_new(L, 1); + + if (deflateInit2(&s->zstream, level, + method, windowBits, memLevel, strategy) != Z_OK) { + lua_pushliteral(L, "call to deflateInit2 failed"); + lua_error(L); + } + + if (dictionary) { + if (deflateSetDictionary(&s->zstream, + (const Bytef *) dictionary, + dictionary_len) != Z_OK) { + lua_pushliteral(L, "call to deflateSetDictionnary failed"); + lua_error(L); + } + } + + s->state = LZ_DEFLATE; + return 1; +} + +static int lz_pushresult (lua_State *L, lz_stream *s) { + if (s->error == Z_OK) { + lua_pushboolean(L, 1); + return 1; + } else { + lua_pushnil(L); + lua_pushstring(L, zError(s->error)); + lua_pushinteger(L, s->error); + return 3; + } +} + +/* + zlib.inflate( + source: string | function | { read: function, close: function }, + windowBits: number, [15] + dictionary: [""] + ) +*/ +static int lzlib_inflate(lua_State *L) { + int windowBits; + lz_stream *s; + int have_peek = 0; + const char *dictionary; + size_t dictionary_len; + + if (lua_istable(L, 1) || lua_isuserdata(L, 1)) { + /* is there a :read function? */ + lua_getfield(L, 1, "read"); + if (!lua_isfunction(L, -1)) { + luaL_argerror( + L, 1, "input parameter does not provide :read function"); + } + lua_pop(L, 1); + /* check for peek function */ + lua_getfield(L, 1, "peek"); + have_peek = lua_isfunction(L, -1); + lua_pop(L, 1); + } + else if (!lua_isstring(L, 1) && !lua_isfunction(L, 1)) { + luaL_argerror( + L, 1, "input must be a string, function, table or userdata value"); + } + + windowBits = luaL_optint(L, 2, 15); + dictionary = luaL_optlstring(L, 3, NULL, &dictionary_len); + + s = lzstream_new(L, 1); + + if (windowBits > 0 && windowBits < 16) { + windowBits |= 32; + } + + if (inflateInit2(&s->zstream, windowBits) != Z_OK) { + lua_pushliteral(L, "call to inflateInit2 failed"); + lua_error(L); + } + + if (dictionary) { + s->dictionary = (const Bytef *) dictionary; + s->dictionary_len = dictionary_len; + } + + s->peek = have_peek; + s->state = LZ_INFLATE; + return 1; +} + +/* + Get block to process: + - top of stack gets +*/ +static const char* lzstream_fetch_block(lua_State *L, lz_stream *s, int hint) { + if (s->i_buffer_pos >= s->i_buffer_len) { + luaL_unref(L, LUA_REGISTRYINDEX, s->i_buffer_ref); + s->i_buffer_ref = LUA_NOREF; + s->i_buffer = NULL; + + lua_rawgeti(L, LUA_REGISTRYINDEX, s->io_cb); + if (!lua_isnil(L, -1)) { + if (lua_isfunction(L, -1)) { + lua_pushinteger(L, hint); + lua_call(L, 1, 1); + } else { + lua_getfield(L, -1, (s->peek ? "peek" : "read")); + lua_insert(L, -2); + lua_pushinteger(L, hint); + lua_call(L, 2, 1); + } + + if (lua_isstring(L, -1)) { + s->i_buffer_pos = 0; + s->i_buffer = lua_tolstring(L, -1, &s->i_buffer_len); + if (s->i_buffer_len > 0) { + s->i_buffer_ref = luaL_ref(L, LUA_REGISTRYINDEX); + } else { + lua_pop(L, 1); + } + } else if (lua_isnil(L, -1)) { + lua_pop(L, 1); + } else { + lua_pushliteral(L, "deflate callback must return string or nil"); + lua_error(L); + } + } else { + lua_pop(L, 1); + } + } + + return s->i_buffer; +} + +static int lzstream_inflate_block(lua_State *L, lz_stream *s) { + if (lzstream_fetch_block(L, s, LZ_BUFFER_SIZE) || !s->eos) { + int r; + + if (s->i_buffer_len == s->i_buffer_pos) { + s->zstream.next_in = NULL; + s->zstream.avail_in = 0; + } else { + s->zstream.next_in = (unsigned char*)(s->i_buffer + s->i_buffer_pos); + s->zstream.avail_in = s->i_buffer_len - s->i_buffer_pos; + } + + s->zstream.next_out = (unsigned char*)s->o_buffer + s->o_buffer_len; + s->zstream.avail_out = s->o_buffer_max - s->o_buffer_len; + + /* munch some more */ + r = inflate(&s->zstream, Z_SYNC_FLUSH); + + if (r == Z_NEED_DICT) { + if (s->dictionary == NULL) { + lua_pushliteral(L, "no inflate dictionary provided"); + lua_error(L); + } + + if (inflateSetDictionary(&s->zstream, s->dictionary, + s->dictionary_len) != Z_OK) { + lua_pushliteral(L, "call to inflateSetDictionnary failed"); + lua_error(L); + } + + r = inflate(&s->zstream, Z_SYNC_FLUSH); + } + + if (r != Z_OK && r != Z_STREAM_END && r != Z_BUF_ERROR) { + lzstream_cleanup(L, s); + s->error = r; + #if 1 + lua_pushfstring(L, "failed to decompress [%d]", r); + lua_error(L); + #endif + } + + if (r == Z_STREAM_END) { + luaL_unref(L, LUA_REGISTRYINDEX, s->i_buffer_ref); + s->i_buffer_ref = LUA_NOREF; + s->i_buffer = NULL; + + s->eos = 1; + } + + /* number of processed bytes */ + if (s->peek) { + size_t processed = s->i_buffer_len - s->i_buffer_pos \ + - s->zstream.avail_in; + + lua_rawgeti(L, LUA_REGISTRYINDEX, s->io_cb); + lua_getfield(L, -1, "read"); + lua_insert(L, -2); + lua_pushinteger(L, processed); + lua_call(L, 2, 0); + } + + s->i_buffer_pos = s->i_buffer_len - s->zstream.avail_in; + s->o_buffer_len = s->o_buffer_max - s->zstream.avail_out; + } + + return s->o_buffer_len; +} + +/* + * Remove n bytes from the output buffer. + */ +static void lzstream_remove(lz_stream *s, size_t n) { + memmove(s->o_buffer, s->o_buffer + n, s->o_buffer_len - n); + s->o_buffer_len -= n; +} + +/* + * Copy at most n bytes to buffer b and remove them from the + * output stream buffer. + */ +static int lzstream_flush_buffer(lua_State *L, lz_stream *s, size_t n, + luaL_Buffer *b) { + /* check output */ + if (n > s->o_buffer_len) { + n = s->o_buffer_len; + } + + if (n > 0) { + lua_pushlstring(L, s->o_buffer, n); + luaL_addvalue(b); + + lzstream_remove(s, n); + } + + return n; +} + +/* z:read( + {number | '*l' | '*a'}* + ) +*/ +static int lz_test_eof(lua_State *L, lz_stream *s) { + lua_pushlstring(L, NULL, 0); + if (s->o_buffer_len > 0) { + return 1; + } else if (s->eos) { + return 0; + } else { + return lzstream_inflate_block(L, s); + } +} + +static int lz_read_line(lua_State *L, lz_stream *s) { + luaL_Buffer b; + size_t l = 0, n; + + luaL_buffinit(L, &b); + + if (s->o_buffer_len > 0 || !s->eos) do { + char *p = s->o_buffer; + size_t len = s->o_buffer_len; + + /* find newline in output buffer */ + for (n = 0; n < len; ++n, ++p) { + if (*p == '\n' || *p == '\r') { + int eat_nl = *p == '\r'; + luaL_addlstring(&b, s->o_buffer, n); + lzstream_remove(s, n+1); + l += n; + + if (eat_nl && lzstream_inflate_block(L, s)) { + if (s->o_buffer_len > 0 && *s->o_buffer == '\n') { + lzstream_remove(s, 1); + } + } + + luaL_pushresult(&b); + return 1; + } + } + + if (len > 0) { + luaL_addlstring(&b, s->o_buffer, len); + lzstream_remove(s, len); + l += len; + } + } while (lzstream_inflate_block(L, s)); + + luaL_pushresult(&b); + return l > 0 || !s->eos || s->o_buffer_len > 0; +} + +static int lz_read_chars(lua_State *L, lz_stream *s, size_t n) { + size_t len; + luaL_Buffer b; + luaL_buffinit(L, &b); + + if (s->o_buffer_len > 0 || !s->eos) do { + size_t rlen = lzstream_flush_buffer(L, s, n, &b); + n -= rlen; + } while (n > 0 && lzstream_inflate_block(L, s)); + + luaL_pushresult(&b); + lua_tolstring(L, -1, &len); + return n == 0 || len > 0; +} + +static int lzstream_decompress(lua_State *L) { + lz_stream *s = lzstream_check(L, 1, LZ_INFLATE); + int nargs = lua_gettop(L) - 1; + int success; + int n; + if (nargs == 0) { /* no arguments? */ + success = lz_read_line(L, s); + n = 3; /* to return 1 result */ + } else { /* ensure stack space for all results and for auxlib's buffer */ + luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments"); + success = 1; + for (n = 2; nargs-- && success; n++) { + if (lua_type(L, n) == LUA_TNUMBER) { + size_t l = (size_t)lua_tointeger(L, n); + success = (l == 0) ? lz_test_eof(L, s) : lz_read_chars(L, s, l); + } + else { + const char *p = lua_tostring(L, n); + luaL_argcheck(L, p && p[0] == '*', n, "invalid option"); + switch (p[1]) { + case 'l': /* line */ + success = lz_read_line(L, s); + break; + case 'a': /* file */ + /* read MAX_SIZE_T chars */ + lz_read_chars(L, s, ~((size_t)0)); + success = 1; /* always success */ + break; + default: + return luaL_argerror(L, n, "invalid format"); + } + } + } + } + if (s->error != Z_OK) { + return lz_pushresult(L, s); + } + if (!success) { + lua_pop(L, 1); /* remove last result */ + lua_pushnil(L); /* push nil instead */ + } + return n - 2; +} + +static int lzstream_readline(lua_State *L) { + lz_stream *s; + int sucess; + + s = lzstream_check(L, lua_upvalueindex(1), LZ_INFLATE); + sucess = lz_read_line(L, s); + + if (s->error != Z_OK) { + return lz_pushresult(L, s); + } + + if (sucess) { + return 1; + } else { + /* EOF */ + return 0; + } +} + +static int lzstream_lines(lua_State *L) { + lzstream_check(L, 1, LZ_INFLATE); + lua_settop(L, 1); + lua_pushcclosure(L, lzstream_readline, 1); + return 1; +} + +static int lzstream_docompress(lua_State *L, + lz_stream *s, + int from, + int to, + int flush) { + int r, arg; + int self = 0; + size_t b_size = s->o_buffer_max; + unsigned char *b = (unsigned char *)s->o_buffer; + + /* number of processed bytes */ + lua_rawgeti(L, LUA_REGISTRYINDEX, s->io_cb); + if (!lua_isfunction(L, -1)) { + self = 1; + lua_getfield(L, -1, "write"); + } + + for (arg = from; arg <= to; arg++) { + s->zstream.next_in = (unsigned char*)luaL_checklstring( + L, arg, (size_t*)&s->zstream.avail_in); + + do { + s->zstream.next_out = b; + s->zstream.avail_out = b_size; + + /* bake some more */ + r = deflate(&s->zstream, flush); + if (r != Z_OK && r != Z_STREAM_END && r != Z_BUF_ERROR) { + lzstream_cleanup(L, s); + lua_pushboolean(L, 0); + lua_pushfstring(L, "failed to compress [%d]", r); + return 2; + } + + if (s->zstream.avail_out != b_size) { + /* write output */ + lua_pushvalue(L, -1); /* function */ + if (self) lua_pushvalue(L, -3); /* self */ + /* data */ + lua_pushlstring(L, (char*)b, b_size - s->zstream.avail_out); + lua_call(L, (self ? 2 : 1), 0); + } + + if (r == Z_STREAM_END) { + lzstream_cleanup(L, s); + break; + } + + /* process all input */ + } while (s->zstream.avail_in > 0 || s->zstream.avail_out == 0); + } + + lua_pushboolean(L, 1); + return 1; +} + +static int lzstream_compress(lua_State *L) { + lz_stream *s = lzstream_check(L, 1, LZ_DEFLATE); + return lzstream_docompress(L, s, 2, lua_gettop(L), Z_NO_FLUSH); +} + +static int lzstream_flush(lua_State *L) { + static int flush_values[] = { Z_SYNC_FLUSH, Z_FULL_FLUSH, Z_FINISH }; + static const char *const flush_opts[] = { "sync", "full", "finish" }; + + lz_stream *s = lzstream_check(L, 1, LZ_DEFLATE); + int flush = luaL_checkoption(L, 2, flush_opts[0], flush_opts); + + lua_settop(L, 0); + lua_pushliteral(L, ""); + return lzstream_docompress(L, s, 1, 1, flush_values[flush]); +} + +static int lzlib_version(lua_State *L) { + lua_pushstring(L, zlibVersion()); + return 1; +} + +static int lzlib_adler32(lua_State *L) { + if (lua_gettop(L) == 0) { + /* adler32 initial value */ + lua_pushnumber(L, adler32(0L, Z_NULL, 0)); + } else { + /* update adler32 checksum */ + size_t len; + int adler = luaL_checkint(L, 1); + const unsigned char* buf = (unsigned char*)luaL_checklstring( + L, 2, &len); + + lua_pushnumber(L, adler32(adler, buf, len)); + } + return 1; +} + +static int lzlib_crc32(lua_State *L) { + if (lua_gettop(L) == 0) { + /* crc32 initial value */ + lua_pushnumber(L, crc32(0L, Z_NULL, 0)); + } else { + /* update crc32 checksum */ + size_t len; + int crc = luaL_checkint(L, 1); + const unsigned char* buf = (unsigned char*)luaL_checklstring( + L, 2, &len); + + lua_pushnumber(L, crc32(crc, buf, len)); + } + return 1; +} + +static int lzlib_compress(lua_State *L) { + size_t avail_in; + const char *next_in = luaL_checklstring(L, 1, &avail_in); + int level = luaL_optint(L, 2, Z_DEFAULT_COMPRESSION); + int method = luaL_optint(L, 3, Z_DEFLATED); + int windowBits = luaL_optint(L, 4, 15); + int memLevel = luaL_optint(L, 5, 8); + int strategy = luaL_optint(L, 6, Z_DEFAULT_STRATEGY); + + int ret; + luaL_Buffer b; + z_stream zs; + + luaL_buffinit(L, &b); + + zs.zalloc = Z_NULL; + zs.zfree = Z_NULL; + + zs.next_out = Z_NULL; + zs.avail_out = 0; + zs.next_in = Z_NULL; + zs.avail_in = 0; + + ret = deflateInit2(&zs, level, method, windowBits, memLevel, strategy); + + if (ret != Z_OK) { + lua_pushnil(L); + lua_pushnumber(L, ret); + return 2; + } + + zs.next_in = (unsigned char*)next_in; + zs.avail_in = avail_in; + + for(;;) { + zs.next_out = (unsigned char*)luaL_prepbuffer(&b); + zs.avail_out = LUAL_BUFFERSIZE; + + /* munch some more */ + ret = deflate(&zs, Z_FINISH); + + /* push gathered data */ + luaL_addsize(&b, LUAL_BUFFERSIZE - zs.avail_out); + + /* done processing? */ + if (ret == Z_STREAM_END) + break; + + /* error condition? */ + if (ret != Z_OK) + break; + } + + /* cleanup */ + deflateEnd(&zs); + + luaL_pushresult(&b); + lua_pushnumber(L, ret); + return 2; +} + +static int lzlib_decompress(lua_State *L) { + size_t avail_in; + const char *next_in = luaL_checklstring(L, 1, &avail_in); + int windowBits = luaL_optint(L, 2, 15); + + int ret; + luaL_Buffer b; + z_stream zs; + + luaL_buffinit(L, &b); + + zs.zalloc = Z_NULL; + zs.zfree = Z_NULL; + + zs.next_out = Z_NULL; + zs.avail_out = 0; + zs.next_in = Z_NULL; + zs.avail_in = 0; + + ret = inflateInit2(&zs, windowBits); + + if (ret != Z_OK) { + lua_pushliteral(L, "failed to initialize zstream structures"); + lua_error(L); + } + + zs.next_in = (unsigned char*)next_in; + zs.avail_in = avail_in; + + for (;;) { + zs.next_out = (unsigned char*)luaL_prepbuffer(&b); + zs.avail_out = LUAL_BUFFERSIZE; + + /* bake some more */ + ret = inflate(&zs, Z_FINISH); + + /* push gathered data */ + luaL_addsize(&b, LUAL_BUFFERSIZE - zs.avail_out); + + /* done processing? */ + if (ret == Z_STREAM_END) + break; + + if (ret != Z_OK && ret != Z_BUF_ERROR) { + /* cleanup */ + inflateEnd(&zs); + + lua_pushliteral(L, "failed to process zlib stream"); + lua_error(L); + } + } + + /* cleanup */ + inflateEnd(&zs); + + luaL_pushresult(&b); + return 1; +} + +#if (LUA_VERSION_NUM >= 502) + +#define luaL_register(L,n,f) luaL_setfuncs(L,f,0) + +#endif + +LUALIB_API int luaopen_zlib(lua_State *L) { + + const luaL_Reg lzstream_meta[] = { + {"write", lzstream_compress }, + {"read", lzstream_decompress }, + {"lines", lzstream_lines }, + {"flush", lzstream_flush }, + {"close", lzstream_close }, + {"adler", lzstream_adler }, + {"__tostring", lzstream_tostring }, + {"__gc", lzstream_gc }, + {NULL, NULL} + }; + + const luaL_Reg zlib[] = { + {"version", lzlib_version }, + {"adler32", lzlib_adler32 }, + {"crc32", lzlib_crc32 }, + {"deflate", lzlib_deflate }, + {"inflate", lzlib_inflate }, + {"compress", lzlib_compress }, + {"decompress", lzlib_decompress }, + {NULL, NULL} + }; + + /* create new metatable for zlib compression structures */ + luaL_newmetatable(L, ZSTREAMMETA); + lua_pushliteral(L, "__index"); + + /* push metatable */ + lua_pushvalue(L, -2); + + /* metatable.__index = metatable */ + lua_rawset(L, -3); + + /* + ** Stack: metatable + */ + luaL_register(L, NULL, lzstream_meta); + + /* remove metatable from stack */ + lua_pop(L, 1); + + /* + ** Stack: + */ + lua_newtable(L); + + lua_pushliteral (L, "_COPYRIGHT"); + lua_pushliteral (L, "Copyright (C) 2003-2010 Tiago Dionizio"); + lua_settable (L, -3); + lua_pushliteral (L, "_DESCRIPTION"); + lua_pushliteral (L, "Lua 5 interface to access zlib library functions"); + lua_settable (L, -3); + lua_pushliteral (L, "_VERSION"); + lua_pushliteral (L, "lzlib 0.4-work3"); + lua_settable (L, -3); + +#define PUSH_LITERAL(name) \ + lua_pushliteral (L, #name); \ + lua_pushinteger (L, Z_##name); \ + lua_settable (L, -3); + +#define PUSH_NUMBER(name, value) \ + lua_pushliteral (L, #name); \ + lua_pushinteger (L, value); \ + lua_settable (L, -3); + + PUSH_LITERAL(NO_COMPRESSION) + PUSH_LITERAL(BEST_SPEED) + PUSH_LITERAL(BEST_COMPRESSION) + PUSH_LITERAL(DEFAULT_COMPRESSION) + + PUSH_LITERAL(FILTERED) + PUSH_LITERAL(HUFFMAN_ONLY) + PUSH_LITERAL(RLE) + PUSH_LITERAL(FIXED) + PUSH_LITERAL(DEFAULT_STRATEGY) + + PUSH_NUMBER(MINIMUM_MEMLEVEL, 1) + PUSH_NUMBER(MAXIMUM_MEMLEVEL, 9) + PUSH_NUMBER(DEFAULT_MEMLEVEL, 8) + + PUSH_NUMBER(DEFAULT_WINDOWBITS, 15) + PUSH_NUMBER(MINIMUM_WINDOWBITS, 8) + PUSH_NUMBER(MAXIMUM_WINDOWBITS, 15) + + PUSH_NUMBER(GZIP_WINDOWBITS, 16) + PUSH_NUMBER(RAW_WINDOWBITS, -1) + + luaL_register(L, "zlib", zlib); + return 1; +} Index: nse_zlib.h =================================================================== --- nse_zlib.h (revision 0) +++ nse_zlib.h (working copy) @@ -0,0 +1,9 @@ +#ifndef ZLIB +#define ZLIB + +#define NSE_ZLIBNAME "zlib" + +LUALIB_API int luaopen_zlib(lua_State *L); + +#endif + Index: scripts/deluge-rpc-brute.nse =================================================================== --- scripts/deluge-rpc-brute.nse (revision 0) +++ scripts/deluge-rpc-brute.nse (working copy) @@ -0,0 +1,156 @@ +local brute = require "brute" +local creds = require "creds" +local nmap = require "nmap" +local shortport = require "shortport" +local stdnse = require "stdnse" +local string = require "string" + +local have_zlib, zlib = pcall(require, "zlib") + +description = [[ +Performs brute force password auditing against the DelugeRPC daemon. +]] + +--- +-- @usage +-- nmap --script deluge-rpc-brute -p 58846 +-- +-- @output +-- PORT STATE SERVICE REASON TTL +-- 58846/tcp open unknown syn-ack 0 +-- | deluge-rpc-brute: +-- | Accounts +-- | admin:default - Valid credentials +-- | Statistics +-- |_ Performed 8 guesses in 1 seconds, average tps: 8 + +author = "Claudiu Perta " +license = "Same as Nmap--See http://nmap.org/book/man-legal.html" +categories = {"intrusive", "brute"} + +portrule = shortport.port_or_service(58846, "", "tcp", "open") + +-- Returns an rencoded login request with the given username and password. +-- The format of the login command is the following: +-- +-- ((0, 'daemon.login', ('username', 'password'), {}),) +-- +-- This is inspired from deluge source code, in particular, see +-- http://git.deluge-torrent.org/deluge/tree/deluge/rencode.py +local rencoded_login_request = function(username, password) + local INT_POS_FIXED_START = 0 + local INT_POS_FIXED_COUNT = 44 + + -- Dictionaries with length embedded in typecode. + local DICT_FIXED_START = 102 + local DICT_FIXED_COUNT = 25 + + -- Strings with length embedded in typecode. + local STR_FIXED_START = 128 + local STR_FIXED_COUNT = 64 + + -- Lists with length embedded in typecode. + local LIST_FIXED_START = 192 + local LIST_FIXED_COUNT = 64 + + -- Encode the login request: + -- ((0, 'daemon.login', ('username', 'password'), {}),) + local request = bin.pack("CCCCACCACAC", + LIST_FIXED_START + 1, + LIST_FIXED_START + 4, + INT_POS_FIXED_START, + STR_FIXED_START + string.len("daemon.login"), + "daemon.login", + LIST_FIXED_START + 2, + STR_FIXED_START + string.len(username), + username, + STR_FIXED_START + string.len(password), + password, + DICT_FIXED_START + ) + return request +end + +Driver = { + + new = function(self, host, port, invalid_users) + local o = {} + setmetatable(o, self) + self.__index = self + o.host = host + o.port = port + o.invalid_users = invalid_users + return o + end, + + connect = function(self) + local status, err + self.socket = nmap.new_socket() + self.socket:set_timeout( + ((self.host.times and self.host.times.timeout) or 8) * 1000) + + local status, err = self.socket:connect(self.host, self.port, "ssl") + if not status then + return false, brute.Error:new("Failed to connect to server") + end + + return true + end, + + disconnect = function(self) + self.socket:close() + end, + + login = function(self, username, password) + if (self.invalid_users[username]) then + return false, brute.Error:new("Invalid user") + end + + local status, err, msq + local request = rencoded_login_request(username, password) + status, err = self.socket:send(zlib.compress(request)) + + if not status then + return false, brute.Error:new("Login error") + end + + status, response = self.socket:receive() + if not status then + + return false, brute.Error:new("Login error") + end + + response = zlib.decompress(response) + if response:match("BadLoginError") then + local error_message = "Login error" + if response:match("Username does not exist") then + self.invalid_users[username] = true + error_message = "Username not found" + elseif response:match("Password does not match") then + error_message = "Username not found" + end + return false, brute.Error:new(error_message) + end + + return true, brute.Account:new(username, password, creds.State.VALID) + end, + + check = function(self) + return true + end +} + +action = function(host, port) + + if not have_zlib then + return "Error: zlib required!" + end + + local invalid_users = {} + local engine = brute.Engine:new(Driver, host, port, invalid_users) + + engine.options.script_name = SCRIPT_NAME + status, results = engine:start() + + return results +end