安全学习记录——渗透篇(一)密码和编码与简单逆向

学了几周的网络了,感觉可以开始搞一搞安全方面的内容了,之前我们说了数据包在网络中的重要性,每个人都可以通过任意构造数据包来任意欺骗任何设备。就算是不懂协议,不懂如何构造数据包的小白,只要会用一些工具,仍然可以进行网络攻击,这种只会借助工具输入命令然后让工具任意进行自动攻击的人也被叫做脚本小子,他们可能连最基础的网关路由程序语言都不懂。而就是这种愣头青造成了全世界最多的网络安全事故。想要保护我们的信息,首先就要防止它被人在网络上截取,就算被截取,也要保证没人能看懂。所以编码和加密就出现了。

编码

编码其实就是一种翻译规则,将字符替换成某些特定的字符,比如“你好=hello”, “蒂姆=tim”就是一种编码,这样当我们传输的参数是“你好蒂姆”时别人就只能看到“hello tim”,如果一个人不懂英语就会一脸懵逼。以前谍战电视剧里不是经常演抢密码本的情节吗,现在的谍战天天混上流社会和靠脑补推理,已经没这些情节了。有的编码甚至可以直接在语言上误导对方,比如将hello mr. sam替换为damn you kal,当对方发现得到的结果是可以读通的,就会下意识地觉得这是原本的意思,而不会去思考字符被替换的可能。当然这只是一种思路,简单来说编码一定是一一对应的,只要知道编码规则,解码就极其简单。那么编码到底有什么用呢,第一句话就说了嘛,翻译。我们在电脑上看见的是汉字而不是01就是编码的结果,将计算机内部的语言翻译成各种其它语言,只要保证我们想要传递信息的对象能看懂即可,不然为什么英语的编码叫encoding。而且还有种用法是多重编码,只要不知道编码顺序就没法看懂,但是这样会有很大的问题,后面逆向时会讲怎么利用这个漏洞。至于怎么编码,怎么解码,百度一搜就知道了,没什么好说的。

加密

我们说到编码其实是一种翻译规则,这种规则是公开的,就好像我们都知道“hello”是“你好”而不是“去你的”一旦人学会了英语,他们就可以做一个翻译器,今后就可以直接靠翻译器交流而不需要重新学一门语言。编码也是一样,我们不需要知道编码规则具体是怎样的,只要知道它的名字就可以依靠各种工具随意编码解码。所以,编码是极度不安全的,一个小白完全可以依靠解码工具读出编码的内容,百度上一堆,于是我们就需要一个新的方法来让传输的字符更加不可控,于是就有了加密。

加密一般有两种,对称和非对称。对称很好理解,我们注册账号需要输入密码,注册后登录账号还是需要输入注册时的密码,加密解密使用同一个码,这就是对称。同理可证,非对称就是加密解码不同码,比如我分享一个百度云文件,提取码是1234,别人看到的其实我账号的一部分,但是绝对不可能靠这个提取码去登录我的账号以看到全部文件,因为我的密码和公开的提取码不是同一个。和编码的区别在于,编码是一种公开规则,是希望有人能看懂的,但是加密的目的就是让人看不懂,而且几乎不可逆。

知道了原理,我们来看看加密是如何工作的,先从对称加密开始,这里以DES为例子:

  • 随便来段字符W = 1234567890abcdef,再来一个密钥key=a860e329be97a923。注意,任何字符最终都会在计算机上变成数字,这个过程所依赖的就是编码,无论输入的是英语还是中文,所以不存在文字怎么加密的情况,文字只是我们看到的像素画而已,计算机读到的不是文字。
  • 然后我们把上面的字符变成二进制得到:B = 00010010 00110100 01010110 01111000 10010000 10101011 11001101 11101111。
  • 然后同样的,把key拿来转换了得到:10101000 01100000 11100011 00101001 10111110 10010111 10101001 00100011
  • 然后建立一张8x8的表,1-64作为序号填进去,然后去掉最后一列只留前面7列,拆成两半,然后开始置换,前面一半从第一列从下往上数57 49 41...,后面一半从63开始往上数,依次将数字按从左往右的第一行去填入。要注意保留原表方便我们看这些格子原本的序号,这个代表的是key转换成2进制后每个数字的序号。
    1, 02, 03, 14, 05, 16, 07, 08, 0
    9, 010, 111, 112, 013, 014, 015, 016, 0
    17, 118, 119, 120, 021, 022, 023, 124, 1
    25, 026, 027, 128, 029, 130, 031, 032, 1
    33, 134, 035, 136, 137, 138, 139, 140, 0
    41, 142, 043, 044, 145, 046, 147, 148, 1
    49, 150, 051, 152, 053, 154, 055, 056, 1
    57, 058, 059, 160, 061, 062, 063, 164, 1
    57494133251798
    158504234261816
    102595143352724
    191136052443632
    6355473931231540
    762544638302248
    146615345372956
    21135282012464
  • 于是我们得到了新的序号,那么把原key按照这个新序号变化一下,得到了key0 = 0111010 0000001 1011011 1110011 1011010 0101100 0001011 0010000,然后再给这key1拆成两半,C0= 0111010 0000001 1011011 1110011;D0= 1011010 0101100 0001011 0010000

  • 然后我们开始将C0,D0的数字进行位移,也就是每个数字向左移动一位,第一位放到最后,每移动一次0+1,所以C1就是1110100 0000011 0110111 1100110,D1=0110100 1011000 0010110 0100001。组合起来就得到了C1D1 = 1110100 0000011 0110111 1100110 0110100 1011000 0010110 0100001。CnDn代表C和D分别向左位移了n次。这个n是可以随意设置的,一般是0-16,28次就相当于还原了,没什么意义。

  • 然后我们再次得到一个顺序表,接着按照这个顺序来再次取数字排列CnDn,排序一次得到key1,排序n次得到keyn。所以key1 = 110011 100010 110010 101111 001010 101111 001100 000100。这个表是固定的,我不知道它是怎么来的,可能是通过反复实验固定下来的,或者基于某些数学原理来确定的,百度,AI都搜不出答案。要是谁知道原理可以说一下。

    1417112415
    3281562110
    2319124268
    1672720132
    425231374755
    304051453348
    444939563453
    464250362932
  • 好了我们开始加密,终于要用到明文B了,还是老套路,1-64的表格,这次我们跳着列从下往上读列,从58 50开始,得到11001100 00011111 11000110 11100000 11110000 10101010 11101000 10100101

    1, 02, 03, 04, 15, 06, 07, 18, 0
    9, 010, 011, 112, 113, 014, 115, 016, 0
    17, 018, 119, 020, 121, 022, 123, 124, 0
    25, 026, 127, 128, 129, 130, 031, 032, 0
    33, 134, 035, 036, 137, 038, 039, 040, 0
    41, 142, 043, 144, 045, 146, 047, 148, 1
    49, 150, 151, 052, 053, 154, 155, 056, 1
    57, 158, 159, 160, 061, 162, 163, 164, 1
  • 接下来,仍然分为两半,L0=11001100 00011111 11000110 11100000,R0=11110000 10101010 11101000 10100101,然后开始计算L1=R0,R1=L0+f(R0, key1),这里的f()是一个扩展,怎么扩展呢,现在R0不是只有32位吗,来继续列个表,保证位数和key1相同。每一行都会重复上一行最后两位再按顺序排列。同理,我们得到了E(R0)=111110 100001 010101 010101 011101 010001 010100 001011,然后E(R0)XORkey1=001101 000011 100111 111010 010111 111110 011000 001111,XOR计算是同一位上相等为0不等为1。0xor1=1
    3212345
    456789
    8910111213
    121314151617
    161718192021
    202122232425
    242526272829
    28293031321
  • 好了重点来了,现在我们得到的E(R0)+key1是一个8段的6bit值,那么每段我们取出头尾组成一个数,换算成十进制,中间的4位数也换算为10进制,得到一个横纵坐标。比如001101,取头尾01,中间0110,换算得(1,6),因为这个是第一段,所以我们要去第一张表S1的1行6列看看是哪个数,然后替换原来的二进制。所以得到了(1,6), (1,1), (3, 3), (2, 13), (1, 11), (2, 15), (0, 12), (1,7),然后查表就好。S盒太多了就不列了,总之结果是13 13 0 2 10 6 5 4,分别转换为二进制 1101 1101 0000 0010 1010 0110 0101 0100
  • 最后将上面一步得到的32bit再拿去进行换位,根据P表来,同样的操作,同样的排序得到R1=0000 0011 1111 1000 1100 0000 1011 1010

    1672021
    29122817
    1152326
    5183110
    282414
    322739
    1913306
    2211425
  • 将L1=R0=1111 0000 1010 1010 1110 1000 1010 0101和R1拼在一起得到11110000 10101010 11101000 10100101 00000011 11111000 11000000 10111010,转换为16进制得到被加密的明文f0aae8a503f8c0ba,加密完成。

从上面的例子来看,对称加密的核心就是通过复杂的运算过程同时增加大量的子密钥,也就是D1C1这种,使得解密所需的成本大大提高。我单是检查错误都感觉脑袋快炸了,因为有个进制转换网站算出来的结果是错的,它最后9位永远是0,最后不得不自己写程序转一遍,再去比对另外的网站的结果。但是对称加密的解密方同样需要逆向上面的步骤来,一旦密钥被偷取,整个加密过程就可逆。对称加密最大的问题在于,很多加密编码过程是在客户端进行的,如果想要加密,那就必须要生成密钥,而且解密也必须要这个密钥,也就是说密钥会随着文件一起传输,这是极度不安全的。因此,对称加密解决的问题其实是针对公开编码和明文的直接爆破。

接下来我们看看非对称的代表RSA:

了解RSA之前我们先看看它的核心,欧拉函数:

  • 假设有一个数为z,有n个数小于等于它且和它互质表示为\Phi \left ( z \right )=n。互质是指相互之间的公约数只有1。注意,这里指的是个数,而不是互质数,1和任何数都互质。
  • 如果说两个数p和q本身都是质数,那么p*q不互质的也就是p的1-q个倍数、q的1-p个倍数以及p*q自己,排除掉这些剩下的数都和它互质,所以\Phi (p\cdot q)=p\cdot q-(q-1)-(p-1)-1=pq-p-q+1=(p-1)(q-1)=\Phi (p)\cdot \Phi (q)
  • 模反数是指如果两个数a和n互质,则选取一个数b使得ab除以n的余数为1,或者ab-1可以被n整除,记录为ab\equiv 1(mod\; n),这个b一定存在,这里就不证明了,这是根据欧拉函数和费马小定理推出的结果。

好了,开始加密吧

  • 首先要求出两个密钥
    选取两个质数p和q
    n = p*q = 7*3 = 21
    z = (p-1)*(q-1) = 6*2 = 12
    
    找一个数d和z互质,d<12,得到解密用的私钥
    d = 5
    私钥secret key(d, n)
    sk(5, 21)
    
    再找一个数e = 17来求加密用的公钥
    d*e == 1(mod z)
    5*17/12=7——1
    于是我们得到公钥public key(e, n)
    pk(17, 21)
    
  • 然后开始加密和解密
    加密明文m=3
    c = mod(m^e, n) = mod(3^17, 21) = 12
    
    解密
    m = mod(c^d, n) = mod(12^5, 21) = 3
    

从上面的步骤可以看出,RSA使用了质因数这个没有规律、无法计算、只能穷举的东西使得逆向工程的工作量和计算量大大提升。而且,在RSA的交换流程下,一个算法只能生成一对公私钥,只有公钥才会参与传输,而私钥是保存在本地的。具体流程是这样:

  • 客户端发送了一个会话请求,服务器返回加密套件和自己的公钥,此时没有内容传输
  • 然后客户端会根据加密套件自己生成一对客户的公私钥,然后根据服务器的公钥将传输文件进行加密,最后把自己的公钥打包在里面一起发过去。这样服务器就可以用自己的私钥读自己公钥加密的内容。
  • 服务响应也是一样,服务器根据客户端提供的公钥来加密内容,同时打包自己的公钥。这样客户也能根据自己的私钥读懂自己公钥加密的文件,并且还能用服务器的公钥再次加密请求。

发现问题了吗,私钥在整个流程中根本不参与任何的传输,只保存在本地,连网卡都不过。知道了加密套件因为难以逆向所以没太大用,知道了公钥也没用,因为这个加密内容根本不是用传输内容上的公钥加密的。所以,非对称加密被认为是安全的,能破解它的只有算力和人为错误。

逆向

随着密码的出现,逆向变成了每一个黑客的梦想,逆向其实不是数学,不需要懂算法,不需要会反推代码;而是一种社会学。最基础的密码破解其实就是穷举,因为最早使用密码锁的设备上密码就那么几位,使用穷举是可以举出来的。后来密码变复杂了,似乎变得很难暴力破解,但是对用户本身而言,过于复杂的密码本身也是在为难自己,为了那么点价值的账号搞几十位大小写数字字符组合的密码完全没必要,每次输入时都是在为难自己,所以大家会把复杂的密码记录在某个地方,可是这样被偷的概率比简单靠脑子记的密码还高,于是干脆设一些简单好记的密码。一些军事设备的密码也会比较简单,为的是能够快速使用,否则一旦忘记那就是一堆废铁。

基于此,弱口令爆破就出现了。爆破其实就是在使用一个预设的、猜测出来的字典,将里面的内容一点一点反复通过数据包发送给服务器,以求得一次成功的响应,说白了就是有一定依据的模糊的穷举。比如大家喜欢用生日设密码,那就收集这个人亲近的所有人的名字和生日然后将字符排列组合起来一个一个试就行了。爆破不仅仅限于密码,数据包中任何内容都可以用来爆破,包括文件、请求、参数、域名等等,范围极广,只要胆子够大,思维够活跃,万物皆可。

但是爆破和逆向有什么关系呢?在抓包的过程中,我们经常会发现出现看不懂的加密编码字符,以前我们拿这个毫无办法,或者有办法逆向但是极其麻烦。现在我们在分析了加密内容的传输流程后会发现一个问题,那就是无论何种加密和编码,保护的都是传输过程,所有的加密解密流程都是在本地完成的,传输出去之后就和本地没有任何关系,加密的那一串字符跟加密没有半毛钱的关系,就是字符而已。服务器读取的并不是原始参数,而是加密字符,能读懂是因为它会解密。所以逆向的方法其实并不是去搞算法,也不是反向分析代码,更不需要一字一句全部读懂。我们需要的是在抓到数据包后,找到可以修改的注入的地方,将我们的文字用本地存在的加密数据包加密一遍,只要发现最终结果相同,那就说明我们成功掌握了字符转换规则,那么,只要将我们的字典全部加密一遍,就变成了专门针对这个网站的爆破字典,这种方法会很比较麻烦,但是绝对是目前效率最高的排查方法,而且是纯手动,比自动化成功的概率会更高。加密方法是现成的,我们要做的只是写脚本而已。不会写脚本?找AI呀。看不懂代码?学呀。

这里是我从网站上获取编码规则后手写的一个脚本,js文件是网页脚本,python是利用网页编码规则来编码自己字段的方法。至于爆破,后面再讲,因为现实中远远没有这么简单。

//array.js,我只修改了最前面的输入内容的部分,把整个文件打包成一个函数方便调用,因为源文件不能批量处理数组。
function allarray(inputArray) {
    var base64 = new Base64();
    var INTEXT2 =[]


        inputArray.forEach(function (item) {
            if (typeof item === 'string') {
                var base64Encoded = base64.encode(item);
                var encodedResult = encodeURIComponent(base64Encoded);
                INTEXT2.push(encodedResult);
            } else {
                console.error('不是字符串', item);
            }
        });
        return INTEXT2


    function Base64() {

        // private property
        _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

        // public method for encoding
        this.encode = function (input) {
            var output = new Array();
            var chr1, chr2, chr3;
            var enc1, enc2, enc3, enc4;
            var i = 0;
            input = _utf8_encode(input);

            while (i < input.length) {
                chr1 = input[i++];
                chr2 = input[i++];
                chr3 = input[i++];

                enc1 = chr1 >> 2;
                enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
                enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
                enc4 = chr3 & 63;
                if (isNaN(chr2)) {
                    enc3 = enc4 = 64;
                } else if (isNaN(chr3)) {
                    enc4 = 64;
                }
                output.push(_keyStr.charAt(enc1) + _keyStr.charAt(enc2) + _keyStr.charAt(enc3) + _keyStr.charAt(enc4));
            }
            return output.join('');
        }

        // public method for decoding
        this.decode = function (input) {
            var output = "";
            var chr1, chr2, chr3;
            var enc1, enc2, enc3, enc4;
            var i = 0;
            input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
            while (i < input.length) {
                enc1 = _keyStr.indexOf(input.charAt(i++));
                enc2 = _keyStr.indexOf(input.charAt(i++));
                enc3 = _keyStr.indexOf(input.charAt(i++));
                enc4 = _keyStr.indexOf(input.charAt(i++));
                chr1 = (enc1 << 2) | (enc2 >> 4);
                chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
                chr3 = ((enc3 & 3) << 6) | enc4;
                output = output + String.fromCharCode(chr1);
                if (enc3 != 64) {
                    output = output + String.fromCharCode(chr2);
                }
                if (enc4 != 64) {
                    output = output + String.fromCharCode(chr3);
                }
            }
            output = _utf8_decode(output);
            return output;
        }

        _utf8_encode = function (string) {
            string = string.replace(/\r\n/g, "\n");
            var utftext = new Array();
            var utftextlen = 0;
            for (var n = 0; n < string.length; n++) {
                var c = string.charCodeAt(n);
                if (c < 128) {
                    utftext[utftextlen++] = c;
                } else if ((c > 127) && (c < 2048)) {
                    utftext[utftextlen++] = (c >> 6) | 192;
                    utftext[utftextlen++] = (c & 63) | 128;
                } else {
                    utftext[utftextlen++] = (c >> 12) | 224;
                    utftext[utftextlen++] = ((c >> 6) & 63) | 128;
                    utftext[utftextlen++] = (c & 63) | 128;
                }

            }
            return utftext;
        }

        _utf8_decode = function (utftext) {
            var string = "";
            var i = 0;
            var c = c1 = c2 = 0;
            while (i < utftext.length) {
                c = utftext.charCodeAt(i);
                if (c < 128) {
                    string += String.fromCharCode(c);
                    i++;
                } else if ((c > 191) && (c < 224)) {
                    c2 = utftext.charCodeAt(i + 1);
                    string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
                    i += 2;
                } else {
                    c2 = utftext.charCodeAt(i + 1);
                    c3 = utftext.charCodeAt(i + 2);
                    string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
                    i += 3;
                }
            }
            return string;
        }

        _exchange_character = function (charArray) {
            charArray = charArray.split("");
            for (var i = 0; i < charArray.length; i++) {

                if (i > 0 && i % 2 == 0) {
                    var c = charArray[i];
                    charArray[i] = charArray[i - 1];
                    charArray[i - 1] = c;
                }
            }
            return charArray.join("");
        }

        this.encodePostParam = function (input) {
            input = this.encode(input).split("").reverse().join("");
            return _exchange_character(input);
        }

        this.decodePostParam = function (input) {
            input = _exchange_character(input).split("").reverse().join("");
            return this.decode(input);
        }
    }
}
import execjs
#文件读取
def read_file_to_array(file_path):
    with open(file_path, 'r', encoding='utf-8') as file:
        lines = file.readlines()
        content_array = [line.strip() for line in lines]
    return content_array
#文本数组转换
def write_array_to_txt(output_array, output_file_path):
    with open(output_file_path, 'w', encoding='utf-8') as file:
        for item in output_array:
            file.write(item + '\n')
#读取js脚本
with open('array.js','r',encoding='utf-8')as f:
    js_code = f.read()
context = execjs.compile(js_code)
#文件输入
input_file_path = 'D:/work/web/sqlDict/sql.txt'
input_array = read_file_to_array(input_file_path)
#使用js处理数组
result_array = context.call('allarray', input_array)
#输出字典
output_file_path = 'D:/work/web/sqlDict/encsql.txt'
write_array_to_txt(result_array, output_file_path)

print(result_array,"all the results are in the file up there.")

  • 17
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: 摘要(Abstract): 本文将讨论如何优化物流流程,以提高运输效率和降低成本。首先,我们将介绍当前物流流程中存在的问题,并探讨这些问题的原因。接着,我们提出了一些解决方案,包括使用新技术和优化路线规划等。最后,我们将讨论这些解决方案的优缺点,并提出未来可能的研究方向。 引言(Introduction): 物流是现代商业活动中至关重要的环节之一。随着全球化和电子商务的发展,物流的重要性越来越突出。然而,传统的物流流程存在许多问题,如路线不合理、配送效率低下等,这些问题影响了企业的利润和顾客的体验。因此,本文旨在探讨如何优化物流流程,以提高运输效率和降低成本。我们将首先介绍当前物流流程中存在的问题,然后提出一些解决方案,并探讨这些解决方案的优缺点。最后,我们将提出未来可能的研究方向。 ### 回答2: 摘要: 逆向物流优化是指为了提高企业的资源利用效率、减少环境污染,通过科学的规划和管理,对回收和再利用的物品进行有效的流转和处理的过程。本文旨在介绍逆向物流优化的重要性和研究的目的,分析逆向物流优化存在的问题,并提出解决方案。 引言: 在现代社会,逆向物流优化变得越来越重要。随着资源的有限性与环境问题的日益突出,逆向物流优化成为了保护环境和提高资源利用效率的一个关键手段。然而,当前的逆向物流系统存在着一些问题,如物品流转速度较慢、处理方式单一、管理不规范等。因此,对逆向物流进行优化是非常必要的。 本研究的目标是通过制定逆向物流优化策略,提高物品流转速度,同时优化再利用和处理方式,从而减少资源浪费和环境污染。 首先,我们将分析逆向物流系统中存在的问题,主要包括流转速度慢、处理方式单一、管理不规范等。通过对问题的深入研究,我们可以找到问题的根本原因。 其次,我们将提出一套逆向物流优化解决方案。在流转速度方面,我们将引入先进的物流技术,如物联网技术和自动化设备,以提高物品流转效率。在再利用和处理方式方面,我们将采用多样化的方法,包括再制造、再生利用和安全处理等,以优化资源利用并减少环境污染。 最后,我们将进行实证研究,验证逆向物流优化策略的可行性和有效性。通过与传统逆向物流系统对比,我们将评估优化策略的效果,以及资源利用和环境影响的改善程度。 总之,逆向物流优化在提高资源利用效率和减少环境污染方面具有重要意义。本研究的目标是通过找出问题、提出解决方案并进行实证研究,为企业和社会提供可行的逆向物流优化策略,以实现可持续发展的目标。 ### 回答3: Abstract 逆向物流是指从消费者到供应商的物流流程,主要涉及产品退货、维修、再制造和再销售等环节。逆向物流的优化可以提高供应链效率、降低成本、满足环境可持续发展的要求。本文通过分析逆向物流的挑战和机遇,探讨如何通过优化逆向物流来提高企业的竞争力。 Introduction 逆向物流作为供应链中重要的环节,扮演着将产品从消费者返回供应商的角色。逆向物流的流程繁杂,涉及到多个环节,例如产品退货、维修、再制造和再销售等。与传统的正向物流相比,逆向物流的管理更加复杂,往往需要考虑不同类型的产品和广泛的处理方式。 逆向物流的优化对于企业来说具有重要意义。首先,优化逆向物流可以提高供应链的效率。通过规范化流程和优化资源分配,企业可以减少物流时间和成本,并提升客户满意度。其次,优化逆向物流可以降低企业的经营成本。通过合理处理产品退货和再利用,企业可以最大限度地降低废品处理费用,提高利润率。最后,优化逆向物流还可以满足环境可持续发展的要求。减少废弃物对环境的影响,积极推动资源循环利用,有助于企业提升可持续发展能力。 然而,逆向物流的优化也面临着一些挑战。首先,逆向物流的流程复杂,需要协调多个环节的合作。此外,由于产品退货可能存在质量问题或损坏,处理过程需要进行诊断和维修,增加了工作量。另外,对于再销售产品,企业还需要考虑市场需求和价格波动的影响。 尽管存在挑战,逆向物流的优化仍然具有巨大的机遇。通过合理利用信息技术和数据分析,企业可以实现逆向物流的智能化管理。此外,与多个利益相关方(例如供应商、销售商和消费者)合作,共同优化逆向物流的流程也是提升企业竞争力的关键。 综上所述,逆向物流的优化是提高供应链效率、降低成本和满足环境可持续发展的要求的重要途径。本文将重点讨论逆向物流的挑战和机遇,并探索如何通过优化逆向物流来提高企业的竞争力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值