在Linux上通过NTLM认证连接到AD服务器(未完结)

这篇文章目前还没有实现具体的功能,只实现了明文登录,因为我缺少一些数据,比如通过密码生成hash,以及通过challenge生成response,我不知道怎么实现,因此这篇文章也是一个交流的文章,希望大佬看见提个建议,我在功能实现后也会补全该文章。

环境:1.服务器 windows server 2022 中文版 AD (推荐下载windows server 2012 R2)

           2.语言:C++

           3.实现流程中的API:依赖openldap 2.6库 

1.NTLM认证是什么?流程是什么?AD服务器是什么?

在这里我不过多述说,推荐还不懂的浏览以下文章,搞懂NTLM流程

http://t.csdnimg.cn/MF2DT

2.通过LDAP连接到AD服务器

2.1:创建LDAP句柄指针

        之后所有的操作都是基于LDAP指针进行操作,例如增删改查AD服务的数据

//ldap是自定义的,uri是string类型的IP地址,端口AD都默认为389 ldap://<IP>:389
LDAP *ldap;
std::string uri = "ldap://192.168.XXX.XXX:389";
int rc = ldap_initialize(&ldap, uri.c_str());if (rc != LDAP_SUCCESS){std::cerr << "ldap_initialize failed: " << ldap_err2string(rc) << std::endl;return rc;}

2.2: 协商ldap的版本

//这些都是固定参数,当然你也可用不协商使用ldap版本,亲测明文登录依旧可以增删改查
int version = LDAP_VERSION3
rc = ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &version);if (rc != LDAP_SUCCESS){std::cerr << "ldap_set_option failed: " << ldap_err2string(rc) << std::endl;return rc;}

2.3协商使用NTLM认证,明文登录不需要做

// 3.设置认证方式为NTLM,我不知道这是否有效,但是服务器却没有拒绝我int option = LDAP_OPT_X_SASL_MECH;const char *mech = "NTLM";rc = ldap_set_option(ldap, option, mech);if (rc = LDAP_OPT_SUCCESS){std::cerr << "Failed to set NTLM authentication mechanism: " << std::endl;return 1;}

2.4进行绑定

2.4.1使用明文进行绑定登录,这非常不安全,通过抓包工具能直接获取到用户的密码

       

//这是一个同步函数,阻塞等待结果
if ((res = ldap_sasl_bind_s(ldap,_dn.c_str(),LDAP_SASL_SIMPLE,_cred.c_str(),NULL, NULL, NULL)) != LDAP_SUCCESS){printf("LDAP BIND FAIL %d:%s\n", res, ldap_err2string(res));}

        参数ldap:上面初始化的ldap句柄指针

        参数_dn:    std::string _dn = "CN=Administrator,CN=Users,DC=test,DC=org";    "CN=<登录的账户名>,CN=<账户所在的组>,DC=<域名前半段>,DC=<域名后半段>"。账户所在

         LDAP_SASL_SIMPLE:进行简单绑定认证

        _cred:  std::string bind_password = "xxxxxxxx";   密码

        后面的3个参数不用管,涉及了更复杂的操作,填写完这些参数,应该就能正常绑定上了

 2.4.2 使用NTLM进行认证绑定,抓包工具能抓不到密码,因为全程没有明文密码的交流,这是我问题所在,两天了一点头绪没有,愁死

  1.根据NTLM的流程,首先要发送账户名和hash来换取challenge响应。但是我不知道如何通过自己的密码生成hash,ldap库也没有这个功能函数(或许是我自己没查到),从第三个参数能看出来这是一个请求。这里的cred包含的不应是密码,而是hash

struct berval cred;cred.bv_val = (char *)bind_password.c_str();cred.bv_len = bind_password.length();// 第一次的第4个参数应该是一个加密hash,如何得到呢rc = ldap_ntlm_bind(ldap, bind_dn.c_str(), LDAP_AUTH_NTLM_REQUEST, &cred, nullptr, nullptr, &msgid_int); // 用您的用户名和密码替换NULL参数if (rc != LDAP_SUCCESS){printf("Error binding to LDAP server with NTLM authentication: %s", ldap_err2string(rc));exit(1);}

2.因为ldap_ntlm_bind是一个异步函数,要使用ldap_result来获取响应以及运行的结果,响应存放在res中,两者通过msgid_int这个参数进行联系

rc = ldap_result(ldap, msgid_int, 0, nullptr, &res);if (rc != LDAP_SUCCESS){printf("ldap_result error\n: %s", ldap_err2string(rc));exit(1);}

3.使用ldap_parse_ntlm_bindresult解析出challenge,存放在challenge中

// 通过解析结果获得challengerc = ldap_parse_ntlm_bind_result(ldap, res, &challenge);if (rc != LDAP_SUCCESS){printf("ldap_parse_ntlm_bind_result: %s", ldap_err2string(rc));exit(1);} 

4.再次调用ldap_ntlm_bin函数向服务器发送通过challenge加密的response,如果与服务器信息对上,那么绑定应该就能成功,与第一个绑定函数的区别在于第三个参数,这里可用看见后缀为RESPONSE,我这里填写challenge是错的,因为我也不知道如通过密码散列将challenge转化为response。

// 这个地方发送的应该是reponse,如何通过密码散列加密challenge,得到reponse呢rc = ldap_ntlm_bind(ldap, bind_dn.c_str(), LDAP_AUTH_NTLM_RESPONSE, &challenge, nullptr, nullptr, &msgid_int); // 用您的用户名和密码替换NULL参数if (rc != LDAP_SUCCESS){printf("Error binding to LDAP server with NTLM authentication: %s", ldap_err2string(rc));exit(1);}

到这里,NTLM如果绑定成功应该就已经结束了,可惜本人才疏学浅,实在不知道如何将passwd生成AD识别的hash,以及将challenge转化为response。国内资料真的寥寥无几,我现在完全没有了研究的方向。希望有大佬看见,能够指定一二,一个星期没有看见自己的进步压力有点大

2.5 通过LDAP句柄指针进行搜索,这里我先简单列一下函数,因为篇幅太长,等后面我会补上,主要时间太紧了,周末就加上详细数据。

1.ldap_search_ext_s:能够搜索指定的属性,例如搜索电话等,并返回结果

2.ldap_first_entry,ldap_next_entry;  两个函数共同作用,遍历结果搜索条目,

3.ldap_first_attributem,ldap_next_attribute ;两个函数共同作用,遍历条目搜索属性

最后只需要判断这个属性是不是你所需要的属性即可。

附上搜索mail例子一份,可自行查看

std::string getEmail(ADServer &server){LDAPMessage *result, *entry;char *attrs[] = {"mail", NULL};// 1.函数能够所搜索你需要查找的信息。LDAP句柄指针,搜索DN(你开始搜索的地方)int rc = ldap_search_ext_s(server.getld(), _dn, LDAP_SCOPE_SUBTREE, "(objectClass=*)", attrs, 0, NULL, NULL, NULL, 1000, &result);if (rc != LDAP_SUCCESS){printf("LDAP SEARCH FAIL %d:%s\n", rc, ldap_err2string(rc));return "";}std::string email;for (entry = ldap_first_entry(server.getld(), result); entry != NULL; entry = ldap_next_entry(server.getld(), entry)){BerElement *ber = NULL;char *attr;for (attr = ldap_first_attribute(server.getld(), entry, &ber); attr != NULL; attr = ldap_next_attribute(server.getld(), entry, ber)){if (std::string(attr) == "mail"){struct berval **vals = ldap_get_values_len(server.getld(), entry, attr);if (vals != NULL){email = std::string(vals[0]->bv_val, vals[0]->bv_len); // Assuming there's only one value for "mail"ldap_value_free_len(vals);}}ldap_memfree(attr);}if (ber != NULL){ber_free(ber, 0);}}ldap_msgfree(result);return email;}

3.参考资料推荐

https://www.openldap.org/software/man.cgi  这是openldap官网,在搜索栏里man一下ldap,就能看到很多的ldap API,同时注意很多API在v3版本已经被禁用。

4.结言 

希望有这方面经验的大佬指定一下,因为代码资料几乎没有,以上全是我摸爬滚打出来的,明文实测可以运行。真期待自己NTLM认证成功的那一天。我也不知道为什么老板要用C++写,听说C#全是封装好的接口,传递一个账户,密码就能通过kerberos,NTLM认证,哎。

如果需要环境搭建的,可以说一下,我周末也写一写。

最后本人应届毕业生菜鸡一个,文章错误很多,仅记录,或许还能逗你一乐

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/180785.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入理解网络IO复用并发模型

本文主要介绍服务端对于网络并发模型以及Linux系统下常见的网络IO复用并发模型。文章内容一共分为两个部分。 第一部分主要介绍网络并发中的一些基本概念以及我们Linux下常见的原生IO复用系统调用&#xff08;epoll/select&#xff09;等。第二部分主要介绍并发场景下常见的网…

el-table树状表格末行合计

首先,由于我的表头是动态的,所以就稍微复杂一点 效果图 表头数据格式是这样的 表格的数据格式是这样的 然后用合并的方法,此处就需要递归去计算,根据props去匹配每一列的数据,然后加起来,关键代码 //合计处理getSummaries(param) {const { columns, data } param;const su…

树结构及其算法-二叉排序树

目录 树结构及其算法-二叉排序树 C代码 树结构及其算法-二叉排序树 事实上&#xff0c;二叉树是一种很好的排序应用模式&#xff0c;因为在建立二叉树的同时&#xff0c;数据已经经过初步的比较&#xff0c;并按照二叉树的建立规则来存放数据&#xff0c;规则如下&#xff1…

解决方案中word中分节符的使用

解决方案中必不可少的两个“符号”&#xff0c;分页符&#xff0c;分节符 有了分节符&#xff0c;可以为不同节设置不同的页眉页脚、分栏格式、纸张大小及方向、页边距、不同节间采用不同的页码序号&#xff0c;常用的功能主要是把word下一次的由原来的“竖版”&#xff0c;变…

深入剖析:正则表达式的奥秘

简介 正则表达式&#xff08;Regular Expressions&#xff09;是一种强大的文本处理工具&#xff0c;一种用于匹配文本模式的字符串。它由特定的字符和操作符组成&#xff0c;用于定义一个搜索模式。这些搜索模式可以用于文本搜索、替换、验证和提取数据等多种用途。 以下是一…

canal+es+kibana+springboot

1、环境准备 服务器&#xff1a;Centos7 Jdk版本&#xff1a;1.8 Mysql版本&#xff1a;5.7.44 Canal版本&#xff1a;1.17 Es版本&#xff1a;7.12.1 kibana版本&#xff1a;7.12.1 软件包下载地址&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1jRpCJP0-hr9aI…

【Python语言】序列(列表,元组,字符串)切片操作

目录 序列切片操作 1.1 对list进行切片&#xff0c;从1开始&#xff0c;到5结束&#xff0c;步长为1 [ 1 : 5 ] 1.2 对tuple进行切片&#xff0c;从头开始&#xff0c;到最后结束&#xff0c;步长为1 [ : ] 1.3 对str进行切片&#xff0c;从头开始&#xff0c;到最…

『精』Vue 组件如何模块化抽离Props

『精』Vue 组件如何模块化抽离Props 文章目录 『精』Vue 组件如何模块化抽离Props一、为什么要抽离Props二、选项式API方式抽离三、组合式API方式抽离3.1 TypeScript类型方式3.2 文件分离方式3.3 对文件分离方式优化 参考资料&#x1f498;推荐博文&#x1f357; 一、为什么要抽…

Cordova插件开发二:高精度定位之卫星数据解析

文章目录 1.最终效果预览2.坐标获取方法3.在公共类中封装获取坐标的通用方法4.插件js中封装startGeoLocation方法5.插件主界面封装的方法1.最终效果预览 2.坐标获取方法 let obj = Object.assign({}, this.mapConfig.mapLocationObj)obj.isKeepCallBack = falselet res = await…

探索无限可能:APITable免费开源多维表格与可视化数据库远程访问的魅力

APITable免费开源的多维表格与可视化数据库公网远程访问 文章目录 APITable免费开源的多维表格与可视化数据库公网远程访问前言1. 部署APITable2. cpolar的安装和注册3. 配置APITable公网访问地址4. 固定APITable公网地址 前言 vika维格表作为新一代数据生产力平台&#xff0c…

代码生成器

Easycode Entity ##导入宏定义 $!{define.vm}##保存文件&#xff08;宏定义&#xff09; #save("/entity", ".java")##包路径&#xff08;宏定义&#xff09; #setPackageSuffix("entity")##自动导入包&#xff08;全局变量&#xff09; $!{au…

半导体工厂将应用哪些制造创新技术?

半导体工厂是高科技产业的结晶&#xff0c;汇聚了世界上最新的技术。 在半导体的原料硅晶片上绘制设计图纸&#xff0c;不产生误差&#xff0c;准确切割并包装&#xff0c;然后用芯片生产出我们使用的电脑、智能手机、手表等各种电子产品。绝大多数半导体厂都采用一贯的工艺&a…

android display 杂谈(三)WMS

用来记录学习wms&#xff0c;后续会一点一点更新。。。。。。 代码&#xff1a;android14 WMS是在SystemServer进程中启动的 在SystemServer中的main方法中&#xff0c;调用run方法。 private void run() { // Initialize native services.初始化服务&#xff0c;加载andro…

【PyTorch实战演练】AlexNet网络模型构建并使用Cifar10数据集进行批量训练(附代码)

目录 0. 前言 1. Cifar10数据集 2. AlexNet网络模型 2.1 AlexNet的网络结构 2.2 激活函数ReLu 2.3 Dropout方法 2.4 数据增强 3. 使用GPU加速进行批量训练 4. 网络模型构建 5. 训练过程 6. 完整代码 0. 前言 按照国际惯例&#xff0c;首先声明&#xff1a;本文只是我…

《Pytorch新手入门》第二节-动手搭建神经网络

《Pytorch新手入门》第二节-动手搭建神经网络 一、神经网络介绍二、使用torch.nn搭建神经网络2.1 定义网络2.2 torch.autograd.Variable2.3 损失函数与反向传播2.4 优化器torch.optim 三、实战-实现图像分类(CIFAR-10数据集)3.1 CIFAR-10数据集加载与预处理3.2 定义网络结构3.3…

2.Docker基本架构简介与安装实战

1.认识Docker的基本架构 下面这张图是docker官网上的&#xff0c;介绍了整个Docker的基础架构&#xff0c;我们根据这张图来学习一下docker的涉及到的一些相关概念。 1.1 Docker的架构组成 Docker架构是由Client(客户端)、Docker Host(服务端)、Registry(远程仓库)组成。 …

【Python基础】Python编程入门自学笔记,基础大全,一篇到底!

&#x1f4e2;&#xff1a;如果你也对机器人、人工智能感兴趣&#xff0c;看来我们志同道合✨ &#x1f4e2;&#xff1a;不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 &#x1f4e2;&#xff1a;文章若有幸对你有帮助&#xff0c;可点赞 &#x1f44d;…

Dubbo捕获自定义异常

一.问题描述 Dubbo远程服务提供者抛出的自定义异常无法被消费方正常捕获&#xff0c;消费方捕获的自定义异常全部变成RuntimeException&#xff0c;使用起来很不方便。 二.原因分析 相关源码 /** Licensed to the Apache Software Foundation (ASF) under one or more* con…

SpringBoot----自定义Start(自定义依赖)

一&#xff0c;为什么要定义Start 向阿里云OSS如果我们要引入的话很麻烦&#xff0c;所以我们可以自定义一些组件&#xff0c; 然后我们只需要在pom文件中引入对应的坐标就可以 二&#xff0c;怎么定义&#xff08;以阿里云OSS为例&#xff09; 1&#xff0c; 定义两个组件模块…

时间序列聚类的直观方法

一、介绍 我们将使用轮廓分数和一些距离度量来执行时间序列聚类实验&#xff0c;同时利用直观的可视化&#xff0c;让我们看看下面的时间序列&#xff1a; 这些可以被视为具有正弦、余弦、方波和锯齿波的四种不同的周期性时间序列 如果我们添加随机噪声和距原点的距离来沿 y 轴…