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

news2024/11/24 17:15:58

这篇文章目前还没有实现具体的功能,只实现了明文登录,因为我缺少一些数据,比如通过密码生成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中

// 通过解析结果获得challenge
    rc = 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.coloradmin.cn/o/1164594.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux的test测试功能

测试文件名的类型&#xff0c;文件是否存在&#xff0c; 文件的权限检测 文件之间的比较 两个整数之间的比较 判断字符串数据 多重条件判定 一个一个来&#xff0c;这个有点多&#xff0c;不过比较有意思&#xff0c;来代码 案例1&#xff0c;判断文件是否存在&#xff…

VS Code提取扩展时出错。XHR failed

需求&#xff1a;想要在扩展中心下载插件&#xff0c;发现报错 原因&#xff1a;vs code之前设置了代理&#xff0c;需要删除即可

【LLM】大模型中的温度系数temperature是啥玩意||底层逻辑

【LLM】大模型中的温度系数是啥玩意_山顶夕景的博客-CSDN博客 大佬两句话就讲明白了&#xff0c;厉害~ 总结一下就是crossentropy里面引入t如下页ppt公式所示&#xff0c;t越大&#xff0c;每个词都有更大的概率被使用&#xff0c;也就体现出了多样性。

基于OR-Tools的装箱问题模型求解(PythonAPI)

装箱问题 一、背包问题&#xff08;Knapsack problem&#xff09;1.1 0-1背包模型基于OR-Tools的0-1背包问题求解&#xff08;PythonAPI&#xff09;导入pywraplp库数据准备声明MIP求解器初始化决策变量初始化约束条件目标函数调用求解器打印结果 1.2 多重背包问题&#xff08;…

74X138元件怎么找——错误解决方法

1.在做74X138的时候根据课本&#xff0c;无法在现有的库中找到74X138&#xff0c;搜索了老师发的库中&#xff0c;都是集成库打不开&#xff0c;那我该怎么办? 根据这个课本P343&#xff0c;&#xff08;即机械工业出版社&#xff0c;刘超&#xff0c;包建荣&#xff0c;俞优姝…

深入理解TCP协议

深入理解TCP 1.TCP基础概念了解 1.1简介 TCP&#xff08;Transmission Control Protocol&#xff09;是一种计算机网络协议&#xff0c;用于在网络上可靠地传输数据。它确保数据的完整性、顺序性和可靠性&#xff0c;通过建立连接、数据分段、错误检测和恢复机制&#xff0c…

什么是DNS

什么是DNS 概述 域名系统&#xff08;英语&#xff1a;Domain Name System&#xff0c;缩写&#xff1a;DNS&#xff09;是互联网的一项服务。它作为将域名和IP地址相互映射的一个分布式数据库&#xff0c;能够使人更方便地访问互联网**。DNS使用[TCP和UDP端口53。当前&#…

【算法练习Day36】最后一块石头的重量 II目标和一和零

​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;练题 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录 最后一块石头的重量 II目标…

2m照片用手机怎么照?三个方法随心选!

在用手机拍照的时候&#xff0c;我们会发现拍出的照片尺寸都很大&#xff0c;占用手机的存储空间较多&#xff0c;而自己又不需要如此高清晰度的照片&#xff0c;那么如何解决这个问题呢&#xff1f;下面介绍了三种方法。 方法一&#xff1a;调整手机拍照的设置选项 1、打开手…

Python---字符串切片-----序列名称[开始位置下标 : 结束位置下标 : 步长]

字符串切片&#xff1a;是指对操作的对象截取其中一部分的操作。字符串、列表、元组都支持切片操作。 本文以字符串为例。 基本语法&#xff1a; 顾头不顾尾&#xff1a; ----------类似range&#xff08;&#xff09; 范围&#xff0c;顾头不顾尾 相关链接Python----ran…

YOLOv5 - yolov5s.yaml 文件

基于深度学习的目标检测模型的结构:输入->主干->脖子->头->输出。主干网络提取特征&#xff0c;脖子提取一些更复杂的特征&#xff0c;然后头部计算预测输出。 YOLOv5网络结构主要由以下几部分组成: 骨干网络(Backbone) &#xff1a;Backbone:骨干网络&#xff0c…

JAVA虚拟机-第2章 Java自动内存管理-异常实践

Java堆溢出 堆的参数设置&#xff1a;将堆的最小值-Xms参数与最大值-Xmx参数设置 public class HeapOOM {static class OOMObject {}public static void main(String[] args) {List<OOMObject> list new ArrayList<OOMObject>();while (true) {list.add(new OO…

FRI及相关SNARKs的Fiat-Shamir安全

1. 引言 本文主要参考&#xff1a; Alexander R. Block 2023年论文 Fiat-Shamir Security of FRI and Related SNARKsAlbert Garreta 2023年9月在ZK Summit 10上分享 ZK10: Fiat-Shamir security of FRI and related SNARKs - Albert Garreta (Nethermind) 评估参数用的Sage…

【Git企业开发】第五节.远程操作

文章目录 前言一、理解分布式版本控制系统二、远程仓库 2.1 新建远程仓库 2.2 克隆远程仓库 2.3 向远程仓库推送 2.4 拉取远程仓库总结 前言 一、理解分布式版本控制系统 我们目前所说的所有内容(工作区&#xff0c;暂存区&#xff0c;版本库等等)&#x…

100G QSFP28 BIDI LR1光模块最新解决方案

上期文章我们有介绍到100G QSFP28 BIDI ER1 Lite光模块&#xff0c;本期内容我们将继续为大家介绍100G光模块系列的100G QSFP28 BIDI LR1光模块。这款产品同样也在易天ECOC光通讯展展出&#xff0c;下面跟着小易一起来看看吧&#xff01; 易天光通信的100G QSFP28 BIDI LR1单纤…

【Linux学习笔记】进程概念(中)

1. 操作系统的进程状态2. Linux操作系统的进程状态3. 僵尸进程4. 孤儿进程5. 进程优先级5.1. 优先级是什么和为什么要有优先级5.2. Linux中的进程优先级 6. 进程切换7. 环境变量7.1. 环境变量的认识7.2. 环境变量相关的命令7.3. 环境变量和本地变量7.4. 命令行参数7.5. 获取环境…

突破防火墙的一种方法

当Linux防火墙阻止来自某个ip的数据时&#xff0c;它应该是根据ip数据报里“源IP地址”字段取得的对方ip吧&#xff0c;那对方就不能通过篡改“源IP地址”来绕过防火墙吗&#xff1f;NAT模式下的路由器就修改了这个字段。 但这样的话&#xff0c;攻击者是收不到服务器返回的数…

通过内网穿透分享本地电脑上有趣的照片:部署piwigo网页

通过cpolar分享本地电脑上有趣的照片&#xff1a;部署piwigo网页 文章目录 通过cpolar分享本地电脑上有趣的照片&#xff1a;部署piwigo网页前言1.Piwigo2. 使用phpstudy网页运行3. 创建网站4. 开始安装Piwogo5. 设定一条内网穿透数据隧道6. 与piwigo网站绑定7. 在创建隧道界面…

k8s 多网卡方案multus

kubernetes 多网卡方案之 Multus_CNI 部署以及基本使用 一、multus cni 出现的背景 在k8s的环境中启动一个容器&#xff0c;默认情况下只存在两个虚拟网络接口&#xff08;loopback 和 eth0&#xff09;&#xff0c; loopback 的流量始终都会在本容器内或本机循环&#xff0c…

CSAPP BOMB LAB part2

bomb lab part2 phase3 汇编语法 switch 汇编版本 switch 例子: switch 使用 jump table movl 指令 cmpl指令是x86汇编语言中的一个比较指令&#xff0c;用于比较两个操作数的值。cmpl指令的格式如下&#xff1a; cmpl source, destinationsource和destination可以是…