国内很多的xxxx单位都需要过安全资质的,有了相应的资质才有资格接安全项目,所以很多白皮书上都有打印机审计,于是催生了下游公司增加这种功能,不过很多只是有这个打印机审计功能,在实际使用的时候又有多少家会真正用这个功能?
目前很多的打印机监控产品或者功能都放在了终端安全产品里了,也就是通常在windows/linux PC上完成,Android需要定制ROM,和手机厂商不是铁兄弟一般是做不了的,MAC就不要想了.
通常的做法有两种,一种是应用层的hook,另外一种是内核的hook.
目前打印机通常是cups,它的实现架构如下,原图:
应用层的hook需要修改打印机守护程序,将任务的转发接口给hook住,通常应用层hook的方法就是封装新库,设置成pre load方式优先链接符号到修改库中.这种方式比较简单,但是cups也是不停地发展,需要适配各个版本的cups程序接口.
另一种是内核的hook,应用程序和打印后台程序总是需要通信的,目前默认/var/run/cups/cups.sock
还有127.0.0.1:631
,后者还好说,使用tcpdump来抓包,前者是unix套接字,高版本内核上的基于ebpf的bcc能够直接抓取,低版本就需要做一点点的编程工作,使用jprobe来完成,下面是一个简单的样本
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <net/sock.h>
#include <net/af_unix.h>
#include <linux/string.h>
#include <linux/inet.h>
static int unix_mkname(char *unix_path, int len, struct socket *sock, struct msghdr *msg)
{
struct sock *peer = NULL;
if (msg->msg_namelen) {
DECLARE_SOCKADDR(struct sockaddr_un *, sunaddr, msg->msg_name);
if (!sunaddr->sun_path[0]) {
unix_path[0] = '@';
strncpy(unix_path + 1, sunaddr->sun_path + 1, len - 2);
} else {
strncpy(unix_path, sunaddr->sun_path, len - 1);
}
} else {
if (unix_sk(sock->sk)->addr) {
if (!unix_sk(sock->sk)->addr->name->sun_path[0]) {
unix_path[0] = '@';
strncpy(unix_path + 1, unix_sk(sock->sk)->addr->name->sun_path + 1, len - 2);
} else {
strncpy(unix_path, unix_sk(sock->sk)->addr->name->sun_path, len - 1);
}
} else {
peer = unix_peer_get(sock->sk);
if (peer && unix_sk(peer)->addr) {
if (!unix_sk(peer)->addr->name->sun_path[0]) {
unix_path[0] = '@';
strncpy(unix_path + 1, unix_sk(peer)->addr->name->sun_path + 1, len - 2);
} else {
strncpy(unix_path, unix_sk(peer)->addr->name->sun_path, len - 1);
}
}
if (peer) sock_put(peer);
}
}
return 0;
}
static int j_unix_stream_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) {
struct iov_iter *i = &msg->msg_iter;
char unix_path[256] = {0};
char *buff = kzalloc(i->iov->iov_len, GFP_ATOMIC);;
unix_mkname(unix_path, sizeof(unix_path), sock, msg);
copy_from_user(buff, i->iov->iov_base, i->iov->iov_len);
.....
kfree(buff);
jprobe_return();
return 0;
}
static struct jprobe jp1 = {
.entry = j_unix_stream_sendmsg,
.kp = {
.symbol_name = "unix_stream_sendmsg",
},
};
static int __init jprobe_init(void)
{
return register_jprobe(jp1);
}
static void __exit jprobe_exit(void)
{
unregister_jprobe(jp1);
}
module_init(jprobe_init)
module_exit(jprobe_exit)
MODULE_LICENSE("GPL");
之后需要解析包,这是另外要给话题了。
上面的两种方式都是将PC当做监控对象,而这个活动中有两个对象,操纵者和被操纵者,我们现在只关心操纵者的行为,换个角度,我们可以关心被操纵者的行为。一种方法是和打印机厂商合作,但是打印机厂商众多,意味着你需要和市面上见到的所有厂商都需要做沟通,说服合作,实现这样一个需求会给他们带来销售额的增长吗?
而另一个方法是在PC和打印机中间做监控,通过监控他们之间的流量和数据实现审计的目的。
1.通过网络镜像的方法镜像所有到打印机的流量。目前打印机基本都是通过网络提供服务的,它有自己的ip,一种是在现有的交换机或者路由上做镜像设置,网络流量到一个PC上做数据分析提取;另一种通过在打印机的网线中间增加一个hub进行流量镜像。
2.进行包检测,目前大部分都是HTTP+ipp方式,这种非常容易解析。不过目前已经支持HTTPS方式了,只不过默认没有使用这种方式
相对于传统的PC端包拦截和检测,我更喜欢后一种,对于目前的业务没有什么大的影响更加轻量级。如果有人能做这样一款小产品的话而且物美价廉相信会有中小型公司会喜欢这个,看一下他们的打印纸都跑哪去了