about 11 results (0.02 seconds)

如何在Linux中用IP转发使内网访问外网?

by LauCyun Feb 6,2018 23:42:58 52,267 views

上周六,几个项目组一起在会议室做产品对接,突然有一设备(只有有线网卡)需要联网,但是会议室又没有有线网口,只有WiFi。那怎么办呢?

最后的方案是:在笔记本(CentOS系统)中用iptables从一个无线网口IP转发到有线网口,这样设备即可上网。

接下来,将介绍如何用iptables从一个无线网口IP转发到有线网口?

实验环境:

  • Router(路由器):
    • 网段:192.168.0.0/24
  • Laptop(笔记本):
    • 系统:CentOS 6
    • 网卡:
      • eth0:192.168.0.100
      • eth1:192.168.56.1
  • PC(内网主机):
    • 系统:CentOS 6
    • 网卡:
      • bond0:192.168.56.2

其实验环境的拓扑图,如下图所示:


图1 实验网络拓扑图

安装上图的拓扑关系,进行搭建实验环境。

1 配置Laptop

1.1 启用IP转发

首先,需要在Laptop中启用IP数据转发,以下两种方法都可行(第一种方法是临时生效;第二种方法是永久生效):

  • 第一种方法:

    修改/proc/sys/net/ipv4/ip_forward文件:

    [root@localhost ~]# echo 1 > /proc/sys/net/ipv4/ip_forward


    图2 启用ip转发

  • 第二种方法:

    修改/etc/sysctl.conf文件,修改成如下:

    [root@localhost ~]# vim /etc/sysctl.conf
    ...
    # Controls IP packet forwarding
    net.ipv4.ip_forward = 1  # 把0改成1
    ...

    执行sysctl -p /etc/sysctl.conf 使其生效。

好了,IP数据转发已经开启了~~

1.2 配置iptables规则

在Laptop中,有两个网卡,分别是:eth0连接Router的网络接口; eth1连接PC的网络接口。

在配置iptables之前,先清空iptables的所有规则:


图3 清空iptables

接着就是配置iptables转发规则,先在filter表中添加一条FORWARD规则,然后在nat表中添加一条POSTROUTING路由规则:


图4 配置iptables转发规则

上面配置的规则,系统重启后会还原。要永久生效就执行service iptables save命令。

1.3 配置eth1

最后就是配置eth1,其IP地址为192.168.56.1,子网掩码为255.255.255.0


图5 配置Laptop的eth1

到此为止,Laptop就配置完成了。

2 配置PC

先给PC配置一个ip,其ip地址为192.168.56.2,如下:


图6 设置IP

接着,就是设置路由了,如下:


图7 设置路由

OK,所有的都配置完成后,测试一下:


图8 ping外网

耶!现在PC可以上外网啦~~~

3 参考

...

Tags Read More..


Kali Linux出现GPG error: The following signatures were invalid: KEYEXPIRED的解决方案

by LauCyun Feb 5,2018 14:38:22 15,655 views

昨天把我的Kali Linux给搞崩了,所以只能新装一个了。

安装完后,运行apt-get update命令时,出现如下错误:

网上有说:

rm -rf /var/lib/apt/lists
apt-get update 

但是,还是不行啊!

Google一番后,看到https://forums.kali.org/showthread.php?24687-Problem-with-apt-get-update&highlight=1425567400#2的方法,于是尝试:

apt-key adv --keyserver hkp://keys.gnupg.net --recv-keys 7D8D0BF6

如上图,竟然可以了!仰天一笑,哈哈哈~~~

如果你是Ubuntu的话,遇到类似的问题,请参考apt - "GPG error:The following signatures were invalid: KEYEXPIRED" - Ask Ubuntu

...

Tags Read More..


OpenSSH漏洞:SSH Weak Algorithms Supported的分析与解决方案

by LauCyun Oct 22,2017 21:10:29 77,363 views

前几天,在公安部三所产品检测的时候,产品爆出一个名为SSH Weak Algorithms Supported的中危漏洞,经过一番沟通后,得知他们用Nessus做的漏洞扫描检测。为此对这个问题稍作了研究和大家分享一下。

1 漏洞描述

如下图,该漏洞为一个中危漏洞,名为SSH Weak Algorithms Supported

SSH Weak Algorithms Supported

该漏洞的详细描述如下图:

大意为Nessus检测到了SSH服务配置中存在Arcfour加密算法或没有配置加密算法。

2 解决方案

在ssh配置文件/etc/ssh/sshd_config中添加下面这行配置。

# CentOS
Ciphers aes128-ctr,aes192-ctr,aes256-ctr,aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se
# Debian/Ubuntu
Ciphers aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com,chacha20-poly1305@openssh.com,blowfish-cbc,aes128-cbc,3des-cbc,cast128-cbc,aes192-cbc,aes256-cbc

保存后,重启ssh服务。

3 漏洞简析

根据Nessus给的描述可以看出,这个漏洞属于SSH的配置缺陷,SSH服务启用了Arcfour(也称RC4)这个不安全算法,我们用man查看一下关于sshd_config文件的帮助,其中可以看到关于Ciphers的条目。

# CentOS6
$ man sshd_config
...
     Ciphers
             Specifies the ciphers allowed for protocol version 2.  Multiple ciphers must be comma-separated.  The supported ciphers are “3des-cbc”, “aes128-cbc”, “aes192-cbc”, “aes256-cbc”, “aes128-ctr”,
             “aes192-ctr”, “aes256-ctr”, “arcfour128”, “arcfour256”, “arcfour”, “blowfish-cbc”, “rijndael-cbc@lysator.liu.se”, and “cast128-cbc”.  The default is:

                aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,
                aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc,
                aes256-cbc,arcfour,rijndael-cbc@lysator.liu.se
...

# Debian/Ubuntu
     Ciphers
             Specifies the ciphers allowed.  Multiple ciphers must be comma-separated.  If the specified value begins with a ‘+’ character, then the specified ciphers will be appended to the default set instead of replacing them.

             The supported ciphers are:

                   3des-cbc
                   aes128-cbc
                   aes192-cbc
                   aes256-cbc
                   aes128-ctr
                   aes192-ctr
                   aes256-ctr
                   aes128-gcm@openssh.com
                   aes256-gcm@openssh.com
                   arcfour
                   arcfour128
                   arcfour256
                   blowfish-cbc
                   cast128-cbc
                   chacha20-poly1305@openssh.com

             The default is:

                   chacha20-poly1305@openssh.com,
                   aes128-ctr,aes192-ctr,aes256-ctr,
                   aes128-gcm@openssh.com,aes256-gcm@openssh.com

             The list of available ciphers may also be obtained using the -Q option of ssh(1) with an argument of “cipher”.

可以看到,在默认的情况下,sshd_config文件中如果没有指定加密算法的话,默认会使用的算法列表中存在Arcfour算法。

因此这个漏洞的修复只需要手动配置ssh加密算法,并去除Arcfour算法即可。

4 Arcfour算法的风险

关于启用Arcfour存在的风险,可以参考Wiki上的词条:RC4 - Wikipedia(需要梯子),没有梯子的请参考:RC4_百度百科

简单的说就是RC4算法本身存在漏洞,在特定情况下,它密文可以被破译得到明文,因此这是一种不安全加密算法。

...

Tags Read More..


基于Lua+pcap实现流量的监控与过滤

by LauCyun Sep 14,2017 23:40:32 13,942 views

在工作中,遇到了一个这样的用例,在每天例行扫描活动中,发现有些应用系统不定期的被扫挂,因为我们不是服务的制造者,没有办法在不同的系统里打印日志,所以我们就想用一个工具来获取特定服务的输入数据流。我们如果不在IDS上看应用的服务,可以直接针对服务所在服务位置,针对应用端口进行,有针对性的监听分析。

1 概述

Tshark、tcpdump和windump这些监听工具提供了比较丰富的命令行参数来监听流量数据。

wireshark、burpsuite这些工具也提供相应的lua、python脚本的机制用于去处理监听的流量数据。但有些场景我们不会使用体积这么大的工具,命令行方式的监听工具又不能加入更多数据处理逻辑,细化对数据的操作。

实际上我们可以自制一个小型的工具,做流量监听,是除了命令联合shell脚本、wireshark、suricata等插件开发的另一种形式。现在很多的监听工具都是基于pcap的,我们基于pcap底层开发一个监听工具。

pcap支持C、python两种开发方式,基于C和pcap库的开发效率比pyton的性能高,这样在高性能的场景python就不太适合,但是从开发效率角度看,用python开发比C又要快很多,毕竟用C开发工具,需要进行边编译,一是有技术门槛,另外的确维护相对比较麻烦。

鉴于以上的原因,既要性能相对够高一些,又能便于维护,在命令行这个粒度上,又可以嵌入自己数据处理逻辑,定制化自己的运行时序,因些,我们选择了C和LUA配合的这种方式。实施方面,就是用C来处理pcap的主件循环,接受pcap监听的buffer数据。然后,将监听的数据通过C与LUA之间的通信,将数据推送给LUA。

数据交给LUA之后,如何管理数据的复杂性就靠LUA的设计方式来解决,因为流量数据是文本流式的,程序原型就想到了pipeline管道的方式进行组织管理。

有了管道的方式,我们就可以在一个监听数据流上,叠加各种插件进地监听数据的处理,可以把复杂的业务,拆解成若干个小的插件处理单元,写作完成任务。

2 pcap的c语言实现

演示原型代码的C部分是很少的,主要的任务是获取buffer的数据,推送lua,代码如下:

#include <stdio.h> 
#include <stdlib.h>  
#include <string.h>
#include <time.h> 

#include <pcap.h> 
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
lua_State* L = NULL;

void getPacket(u_char * arg, const struct pcap_pkthdr * pkthdr, const u_char * packet) { 

  L = lua_open();
      luaL_openlibs(L);

  if (luaL_loadfile(L, "buffer.lua") || lua_pcall(L, 0,0,0))
      printf("Cannot run configuration file:%s", lua_tostring(L, -1));

  lua_getglobal(L, "buffer");

  lua_newtable(L); 
  int idx = 0;
  for (idx=1; idx < pkthdr->len; idx++) {
      lua_pushnumber(L, idx);  
      lua_pushnumber(L, packet[idx]);  
      lua_settable(L, -3);  
  }

  lua_pcall(L, 1,0,0);

  int * id = (int *)arg;  
  printf("id: %d\n", ++(*id));  
  printf("Packet length: %d\n", pkthdr->len);  
  printf("Number of bytes: %d\n", pkthdr->caplen);  
  printf("Recieved time: %s", ctime((const time_t *)&pkthdr->ts.tv_sec));   
  printf("\n\n");  
}  
  
int main()  
{  
  char errBuf[PCAP_ERRBUF_SIZE], * devStr;  
    
  /* get a device */  
  //devStr = pcap_lookupdev(errBuf);  
  devStr = "ens33";
    
  if(devStr) {  
    printf("success: device: %s\n", devStr);  
  } else {  
    printf("error: %s\n", errBuf);  
    exit(1);  
  }  
    
  /* open a device, wait until a packet arrives */  
  pcap_t * device = pcap_open_live(devStr, 65535, 1, 0, errBuf);  
    
  if(!device) {  
    printf("error: pcap_open_live(): %s\n", errBuf);  
    exit(1);  
  }  
    
  /* construct a filter */  
  struct bpf_program filter;  
  //pcap_compile(device, &filter, "src port 80", 1, 0);  
  pcap_compile(device, &filter, "dst port 80", 1, 0);  
  pcap_setfilter(device, &filter);  
    
  /* wait loop forever */  
  int id = 0;  
  pcap_loop(device, -1, getPacket, (u_char*)&id);  
  pcap_close(device);  
  
  return 0;  
}  

c部分将监听的流量buffer的数据,以数组的形式给lua,在lua中array其实就是一个table,我们在lua部分重组了一下数组数据,生成了一个字符串,代码如下:

buffer = function(tbl)
    local tmpstr=''
    for k,v in pairs(tbl) do
        tmpstr = tmpstr..string.char(v)
    end
    io.write(tmpstr,"\n")
end

编译c程序就靠下面的命令行,后期我们也可以生成一个makefile简化编译流程。

$ gcc watch.c -I/usr/include/lua5.1 -ldl -lm -llua5.1 -lpcap -o watch

为了方便 ,我们写了一个Makefile

LUALIB=-I/usr/include/lua5.1 -lpcap -ldl -lm -llua5.1 

.PHONY: all win linux

all:
        @echo Please do \'make PLATFORM\' where PLATFORM is one of these:
        @echo win linux

win:

linux: watch

watch : watch.c
         gcc $^ -o$@ $(LUALIB) 
clean:
        rm -f watch 

3 Lua与管道插件设计

为什么要使用管道插件的方式拆分和组织模块?以什么形式传送数据变成了一个手艺,解耦最直接的方法是分层,先把数据与为业分开,再把业务代码和共通代码分开。数据层对我们系统来说就是规则,系统使用的共通代码都封装到了框架层,而系统功能业务共通的部分,以插件为机能单位分开并建立联系。数据是面象用户的,框架是面向插件开发者的, 插件的实现就是机能担当要做的事情,不同的插件组合相对便捷的生成新机能,也是插件便利的益处与存在的意义。

因为管道中的插件是会被顺序调用的,因此插件模板中的initaction函数也会被正常的回调,而这些回调函数在被调用时,管道系统会把流数据push给单元插件,而接到数据流的插件在接到回调push过来的数据后,进行相应的判断筛选,将编辑后的数据通过sink插槽push给后面的插件,直到管道尾端的插件报警或是记日志,一次管道启动运行的时序就结束了。

图1 pipeline示意图

我们用代码说明管道的实现更直观,代码如下:

local pipeline = require "pipeline"
local status = pipeline:new {
    require"plugin.source_plugin",
    require"plugin.filter_plugin",
}
return pipeline

字符型式的管道图示:

+---------------+     +-----------------+

| source-plugin |     |  filter-plugin  |

               src - sink              src 

+---------------+     +-----------------+ 

我们通过LUA特有的类组织方式构建了一个顺序的管道数据结构,管道中的插件是按声明的先后顺序来执行的。pipeline管道程序的主要逻辑就是管理回调函数的调用,代码如下:

local Pipeline = {}
local Pobj = {}


function Pipeline.output(self, list, flg)
    if flg == 0 then
        return 
    end

    for k,v in pairs(list) do
        print(k,v)
    end
end

function Pipeline.new(self, elements)
    self.element_list = elements
    self:output(elements, 0)
    return PObj
end

function Pipeline.run(self, pcapdata)
    local src = {
        metadata= { 
            data= pcapdata,
            request = {
                uri="https://www.laucyun.com"
            }
        }
    }
    for k,v in pairs(self.element_list) do
        v:init()
        v:push(src)
        local src, sink = v:match(pcapdata)
        if type(sink) == "table" then
            self:output(sink, 0)
        end
        src = sink
    end
end

return Pipeline

插件抽像出了几个特的函数给开发用户,时序是事先设计好的,最主要的数据和回调也明确了,主要是Pipeline.run统一回调了几个模板的函数,initpushmatch函数,这样顶层的设计几乎是固定的,之后所有的业务逻辑都在模板了,按这个时序执行,而插件之间的数据传递依靠的就srcsink这个插件。

基于管道插件的设计特点就是之前的插件会把源头的数据推送给后面的插件,如果管道中的数据在之前被编辑过,会体现在后面的插件接受数据后看见变化,具体的实现,代码如下:

local source_plugin = {}
local src = {
   args="source args"
}
local sink = {
    name = "source_plugin",
    ver = "0.1"
}
function source_plugin.output(self, list, flg)
    if flg == 0 then
        return
    end
    for k,v in pairs(list) do
        print(k,v)
    end
end
function source_plugin.push(self, stream) 
    for k,v in pairs(stream.metadata) do
        self.source[k]=v
    end 
end
function  source_plugin.init(self)
    self.source = src
    self.sink = sink
end
function source_plugin.action(self, stream) 
end
function  source_plugin.match(self, param)
    self.sink['found_flg']=false
    for kn,kv in pairs(self.source) do
         self.sink[kn] = kv
    end
    self.sink['metadata'] = { data=self.source['data'] }
    self:action(self.sink)
    return self.source, self.sink
end
return  source_plugin

source_plugin是一个典型的插件模板,所有被pipeline回调函数都一目了然,但对于插件的使用来说,可以完全不用关心内部细节,只关心一个函数就行了,就action(self, stream)这个函数,能提供的所有数据都已经被保存到stream这个数据结构里了,对监听的所有后期处理都从这里开始。如果创建一个新插件呢?就是复制源文件改一个名就行了,创建了一个filter_plugin的插件,代码如下:

local filter_plugin = {}
local src = {
   args="filter args"
}
local sink = {
    name = "filter_plugin",
    ver = "0.1"
}
function filter_plugin.output(self, list, flg)
    if flg == 0 then
        return
    end
    for k,v in pairs(list) do
        print(k,v)
    end
end
function filter_plugin.push(self, stream) 
    for k,v in pairs(stream.metadata) do
        self.source[k]=v
    end 
end
function  filter_plugin.init(self)
    self.source = src
    self.sink = sink
end
function filter_plugin.action(self, stream) 
    io.write(stream.data, "\n")
end
function  filter_plugin.match(self, param)
    self.sink['found_flg']=false
    for kn,kv in pairs(self.source) do
         self.sink[kn] = kv
    end
    self.sink['metadata'] = { data=self.source['data'] }
    self:action(self.sink)
    return self.source, self.sink
end
return  filter_plugin

生成了这个文件,我们在管理里加入这个插件就OK了,代码:

local pipeline = require "pipeline"
local status = pipeline:new {
    require"plugin.source_plugin",
    require"plugin.filter_plugin",
    require"plugin.syslog_plugin",
}
return pipeline

管道图示:

+---------------+     +-----------------+     +------------------+

| source-plugin |     |  filter-plugin  |     | syslog-plugin    |  

               src - sink              src - sink                ....

+---------------+     +-----------------+     +------------------+

我们在这个管道图示的后面,看到多了一个syslog-plugin的插件,这个插件追加的功能就是将前面插件处理的流数据,通过syslog协议,将数所存到远端的syslog服务器上,集中到大数据日志中心进行分析展示,这样这个程序就是一个简单的监控代理的模型。下面我们将程序过行起来,看一下执行的效果。

4 应用实例 

当你取得了流量数据后,理论上我们想干什么,由我们的想象力决定,在实际的应用场景中,我们像不深入一个应用的部分,就想得到这个应用的输入数据,比如这个应用是一个HTTP SEVER,Openrety服务,我们能不能通过启动这个监听程序,来取得对某个nginx服务的用户请求的agent数据呢,其实这个演示程序可以做到,我们构造一个简单的请求。

$ curl www.laucyun.com

然后我们,启动这个脚本程序:

$ ./watch


图2 演示请求laucyun.com的匹配结果

我们只是在filter_plugin这个lua插件中,对action()回调函数,添加了一个简单的处理,就捕获到了Host的信息含有laucyun.com的数据。

function filter_plugin.action(self, stream) 
    io.write(stream.data, "\n")
    local flg = string.find(stream.data, "laucyun.com")
    if flg then 
	print("###########[ OK ]#############")
    end
end

5 总结

实际上我们通过把流量数据转发给Lua,让Lua处理更高级的数据检索需求,在实际的工作中,有些应用的访问者会给出非正常的垃圾信息。如果某些应用输入脏数据,直接会造成程序崩溃,程序又不输出日志,这种机制的流量监听就会有应用场景了,比方说,我们进行大量的扫描行为了,会发出一些某些程序之前预料之外的数据,为了还原是具体那条扫描把程序弄挂了,我们就可以灵活的写一个lua插件,捕获脏数据。

这程序只是一个抛砖引玉,我们直接通过C加Lua的方式,灵感来自至Nginx + lua ,  就是现在流行的openresty服务器,又可以用到C的高性能,又使用Lua提高了后续处理的灵活性。如果要处理更大流量的单机流量监听,应该后续加入环形buffer缓存数据,如果直接将日志数据syslog到远端口的syslog服务上,我们就可以使lua开发一个插件,做syslog转发就好,这就是当时考虑使用lua管道设计做这个实验工具的目地。

源码:http://github.laucyun.com/luapcap

...

Tags Read More..


Compile Raspberry Pi Kernel

by LauCyun May 28,2017 09:52:24 13,808 views

使用官方给的镜像搭建好了树莓派的开发环境,可以说已经可以上手应用了,但是如果官方提供的内核有些功能不能满足我们的需要或者需要对内核进行部分裁剪,那么就需要对树莓派的内核进行裁剪,本篇将讲解如何自己编译最新的 Linux Kernel 给你的 Raspberry Pi 使用。
1. 下载编译工具、Kernel源文件、固件 Firmware

下载地址:https://github.com/raspberrypi

上面列出了树莓派所有的开源软件:

  • firmware:树莓派的交叉编译好的二进制内核、模块、库、bootloader
  • linux:内核源码
  • tools:编译内核和其他源码所需的工具——交叉编译器等

我们只需要以上三个文件即可,下面的源码可以了解一下:

  • documentation:树莓派离线帮助文档,教你如何使用、部署树莓派(树莓派官方使用教程)
  • userland:arm 端用户空间的一些应用库的源码——vc 视频硬浮点、EGL、mmal、openVG 等
  • hats:Hardware Attached on Top,树莓派 B+ 型板子的扩展板资料
  • maynard:一个 gtk 写成的桌面环境
  • scratch:一个简易、可视化编程环境
  • noobs:一个树莓派镜像管理工具,他可以让你在一个树莓派上部署多个镜像
  • weston:一个应用程序
  • target_fs:树莓派最小文件系统,使用 busybox 制作
  • quake3:雷神之锤 3 有线开发源码 firmwareb

下载源码:

$ mkdir raspeberrypi_src
$ cd raspberrypi_src
$ git clone git://github.com/raspberrypi/firmware.git
$ git clone git://github.com/raspberrypi/linux.git
$ git clone git://github.com/raspberrypi/tools.git

会得到三个文件夹:firmware、linux、tools

图1 编译工具、Kernel源文件、固件 Firmware

 

2. 编译、提取内核及其模块

2.1 获得内核配置文件

在运行的树莓派中运行

$ ls /proc/

可看到一个叫 config.gz 的文件,他是当前的树莓派配置选项记录文件,我们将他拷出,放入我们的内核源码目录树下。

$ cp /proc/config /home/pi

我们这里使用前面交过的 samba 拷出并拷入内核源码目录下,不熟悉的人可参考前面文章。

在 linux 内核源码下执行

$ zcat config.gz > .config

2.2 配置、编译内核

修改内核源码 makefile ARCH 类型和编译器路径$vi Makefile +195,找到以上类似代码,改为如图所示。

查看、修改配置选项$make menuconfig,可出现以下界面。

如果不做修改,直接选中 exit 即可(注意使用键盘操作)。

编译内核镜像$makearch/arm/boot目录下可以看到一个叫zImage的文件,就是我们新的内核,但是树莓派需要另外一种格式的镜像,需要进行处理一下,执行以下命令

$ cd tools/mkimage

$./imagetool-uncompressed.py ../../linux/arch/arm/boot/zImage

即可在当前文件夹下看到一个叫kernel.img的文件,就是我们需要的新内核了。

提取 modules 上一步其实不但编译出来了内核的源码,一些模块文件也编译出来了,这里我们提取一下,

$ cd raspberrypi_src
$ mkdir modules
$ cd linux
$ make modules_install INSTALL_MOD_PATH=../modules

即可在 modules 得到我们需要的模块文件。

...

Tags Read More..